package service

import (
	"fmt"
	ClickHouse "gin/database"
	"gin/model"
	"gin/types"
	"gorm.io/gorm"
	"strconv"
	"strings"
	"time"
)

type ScheduleInfo struct {
}
type UserItem struct {
	Id   uint64 `json:"id"`
	Name string `json:"name"`
}
type EpisodeInfoItem struct {
	Id   uint64 `json:"id"`
	Name string `json:"name"`
	Code string `json:"code"`
}

var notCurrentMonthItem = types.CardInfo{}

var currentMonthItem = types.CardInfo{}

var StatusListMap = func() (res map[string]uint64) {
	var statusList []struct {
		Id   uint64 `json:"id"`
		Name string `json:"name"`
		Code string `json:"code"`
	}
	var statusMap = make(map[string]uint64)
	ClickHouse.DB.Model(&model.Status{}).
		Find(&statusList)
	for _, v := range statusList {
		statusMap[v.Code] = v.Id
	}
	res = statusMap
	return
}

func MonthIntervalTime(timeLayout string, d string) (startTime, endTime int64) {
	loc, _ := time.LoadLocation("Local") //重要：获取时区
	if d == "" {
		local := time.Now()
		d = local.Format(timeLayout)
	}
	theTime, _ := time.ParseInLocation(timeLayout, d, loc) //使用模板在对应时区转化为time.time类型
	monthFirstTime := theTime.AddDate(0, 0, -theTime.Day()+1)
	startTime = GetMonthUnix(monthFirstTime, "first")
	monthLastTime := theTime.AddDate(0, +1, -theTime.Day()+1)
	endTime = GetMonthUnix(monthLastTime, "last")
	return startTime, endTime
}

func GetMonthUnix(d time.Time, timeType string) int64 {
	sec := 0
	if timeType == "last" {
		sec = -1
	}
	return time.Date(d.Year(), d.Month(), d.Day(), 0, 0, sec, 0, d.Location()).Unix()
}

// Count 非标准项目排期任务完成统计
func (S ScheduleInfo) Count(tenantId int64, userId int64, projectId uint64, isAll string, stepCategoryId uint64, currentTime string) (res types.CountRes, err error) {

	// 非标准统计
	tmpNonStandard, err := S.ScheduleNonStandardProjectTaskCompletionCount(tenantId, userId, projectId, isAll, stepCategoryId, currentTime)
	// 标准
	tmpStandard, err := S.ScheduleStandardProjectTaskCompletionCount(tenantId, userId, projectId, stepCategoryId, currentTime)

	res.NotStandardCount = tmpNonStandard.CountCurrentMonthCompletion + tmpNonStandard.CountNotCurrentMonthCompletion
	res.StandardCount = tmpStandard
	return
}

// DeliverList 交付列表
func (S ScheduleInfo) DeliverList(stepCategoryId int64, month string, projectId int64, userId, tenantId int64) (res types.DeliverRes, err error) {
	fromTimestamp, toTimestamp := MonthIntervalTime("2006-01", month)

	var projectService Project
	totalProjectIdList, err := projectService.GetUserProjectByIds(userId, tenantId)

	if len(totalProjectIdList) == 0 {
		return
	}

	var statusService Status
	notStartedIdList, _ := statusService.GetStatusIdsByCorrespond([]string{"not_started"})
	inProgressIdList, _ := statusService.GetStatusIdsByCorrespond([]string{"in_progress", "daily", "feedback"})
	doneIdList, _ := statusService.GetStatusIdsByCorrespond([]string{"done"})

	var scheduleTaskCountRes []types.ScheduleTaskCountItemQuery
	var countModuleList []model.Module
	err = ClickHouse.DB.Model(&model.Module{}).Where("code in ?", []string{"design", "asset", "level", "shot"}).Find(&countModuleList).Error
	if err != nil {
		return
	}
	var countModuleMap = make(map[string]*model.Module)
	var countModuleIdList = make([]int64, len(countModuleList))
	for i, module := range countModuleList {
		countModuleMap[module.Code] = &countModuleList[i]
		countModuleIdList[i] = module.Id
	}

	query := ClickHouse.DB.Model(&model.Entity{}).Joins("e join task t on e.id = t.entity_id").
		Where("e.module_id in (?) and e.project_id in (?) and t.step_category_id = ? and t.step_type = 'step'", countModuleIdList, totalProjectIdList, stepCategoryId).
		Select("multiIf(e.module_id = "+strconv.FormatInt(countModuleMap["design"].Id, 10)+", simpleJSONExtractString(e.json, 'design_grade'),"+
			"e.module_id = "+strconv.FormatInt(countModuleMap["asset"].Id, 10)+","+
			"simpleJSONExtractString(e.json, 'asset_grade'),"+
			"e.module_id = "+strconv.FormatInt(countModuleMap["level"].Id, 10)+","+
			"simpleJSONExtractString(e.json, 'level_grade'),"+
			"e.module_id = "+strconv.FormatInt(countModuleMap["shot"].Id, 10)+", '', '未知') entity_grade,"+
			"multiIf(e.module_id = "+strconv.FormatInt(countModuleMap["design"].Id, 10)+", "+
			"simpleJSONExtractString(e.json, 'design_category'), e.module_id = "+strconv.FormatInt(countModuleMap["asset"].Id, 10)+","+
			"simpleJSONExtractString(e.json, 'asset_category'), e.module_id = "+strconv.FormatInt(countModuleMap["level"].Id, 10)+","+
			"simpleJSONExtractString(e.json, 'level_category'), e.module_id = "+strconv.FormatInt(countModuleMap["shot"].Id, 10)+", '镜头', '未知') entity_category,"+
			"count((t.plan_end_time >= ? and t.plan_end_time <= ? and "+
			"simpleJSONExtractInt(t.json, 'task_status') in (?)) or null) plan_inside_not_started,"+
			"count((t.plan_end_time >= ? and t.plan_end_time <= ? and "+
			"simpleJSONExtractInt(t.json, 'task_status') in (?)) or null) plan_inside_inprogress,"+
			"count((t.plan_end_time >= ? and t.plan_end_time <= ? and "+
			"simpleJSONExtractInt(t.json, 'task_status') in (?)) or null) plan_inside_done,"+
			"count((t.plan_end_time >= ? and t.plan_end_time <= ? and "+
			"simpleJSONExtractInt(t.json, 'task_status') in (?) and "+
			"simpleJSONExtractString(t.json, 'task_is_overdue') = 'yes') or null) plan_inside_overdue,"+
			"count((t.plan_start_time < ? and t.plan_end_time > ? and "+
			"simpleJSONExtractInt(t.json, 'task_status') in (?)) or null) plan_outside_not_started,"+
			"count((t.plan_start_time < ? and t.plan_end_time > ? and "+
			"simpleJSONExtractInt(t.json, 'task_status') in (?)) or null) plan_outside_inprogress,"+
			"count((t.plan_start_time < ? and t.plan_end_time > ? and "+
			"simpleJSONExtractInt(t.json, 'task_status') in (?)) or null) plan_outside_done",
			fromTimestamp, toTimestamp, notStartedIdList,
			fromTimestamp, toTimestamp, inProgressIdList,
			fromTimestamp, toTimestamp, doneIdList,
			fromTimestamp, toTimestamp, notStartedIdList,
			toTimestamp, toTimestamp, notStartedIdList,
			toTimestamp, toTimestamp, inProgressIdList,
			toTimestamp, toTimestamp, doneIdList,
		).
		Where("JSONLength(JSONExtractString(t.json, 'task_deprecate_data')) = 0").
		Group("entity_grade,entity_category")

	if projectId > 0 {
		query.Where("e.project_id = ?", projectId)
	}

	err = query.Find(&scheduleTaskCountRes).Error
	if err != nil {
		return
	}

	var currentCardInfoMap = make(map[string]*types.CardInfoItemStruct, 0)

	var currentCardInfoResMap = map[string][]*types.CardInfoItemStruct{
		"not_started": {},
		"processing":  {},
		"completed":   {},
		"overdue":     {},
	}
	var currentCardInfoList []types.CardInfoItemStruct
	var notCurrentCardInfoMap = make(map[string]*types.CardInfoItemStruct, 0)

	var notCurrentCardInfoResMap = map[string][]*types.CardInfoItemStruct{
		"not_started": {},
		"processing":  {},
		"completed":   {},
	}
	var notCurrentCardInfoList []types.CardInfoItemStruct

	var currentIndex, notCurrentIndex = 0, 0
	for _, re := range scheduleTaskCountRes {

		// 计划内
		if re.PlanInsideNotStarted > 0 {
			if _, ok := currentCardInfoMap["not_started"+re.EntityGrade+re.EntityCategory]; !ok {
				currentCardInfoList = append(currentCardInfoList, types.CardInfoItemStruct{
					Name1: re.EntityGrade,
					Name2: re.EntityCategory,
					Num:   re.PlanInsideNotStarted,
				})
				currentCardInfoMap["not_started"+re.EntityGrade+re.EntityCategory] = &currentCardInfoList[currentIndex]
				currentCardInfoResMap["not_started"] = append(currentCardInfoResMap["not_started"], &currentCardInfoList[currentIndex])
				currentIndex += 1
			} else {
				currentCardInfoMap["not_started"+re.EntityGrade+re.EntityCategory].Num += re.PlanInsideNotStarted
			}
		}
		if re.PlanInsideInprogress > 0 {
			if _, ok := currentCardInfoMap["processing"+re.EntityGrade+re.EntityCategory]; !ok {
				currentCardInfoList = append(currentCardInfoList, types.CardInfoItemStruct{
					Name1: re.EntityGrade,
					Name2: re.EntityCategory,
					Num:   re.PlanInsideInprogress,
				})
				currentCardInfoMap["processing"+re.EntityGrade+re.EntityCategory] = &currentCardInfoList[currentIndex]
				currentCardInfoResMap["processing"] = append(currentCardInfoResMap["processing"], &currentCardInfoList[currentIndex])
				currentIndex += 1
			} else {
				currentCardInfoMap["processing"+re.EntityGrade+re.EntityCategory].Num += re.PlanInsideInprogress
			}
		}
		if re.PlanInsideDone > 0 {
			if _, ok := currentCardInfoMap["completed"+re.EntityGrade+re.EntityCategory]; !ok {
				currentCardInfoList = append(currentCardInfoList, types.CardInfoItemStruct{
					Name1: re.EntityGrade,
					Name2: re.EntityCategory,
					Num:   re.PlanInsideDone,
				})
				currentCardInfoMap["completed"+re.EntityGrade+re.EntityCategory] = &currentCardInfoList[currentIndex]
				currentCardInfoResMap["completed"] = append(currentCardInfoResMap["completed"], &currentCardInfoList[currentIndex])
				currentIndex += 1
			} else {
				currentCardInfoMap["completed"+re.EntityGrade+re.EntityCategory].Num += re.PlanInsideDone
			}
		}
		if re.PlanInsideOverdue > 0 {
			if _, ok := currentCardInfoMap["overdue"+re.EntityGrade+re.EntityCategory]; !ok {
				currentCardInfoList = append(currentCardInfoList, types.CardInfoItemStruct{
					Name1: re.EntityGrade,
					Name2: re.EntityCategory,
					Num:   re.PlanInsideOverdue,
				})
				currentCardInfoMap["overdue"+re.EntityGrade+re.EntityCategory] = &currentCardInfoList[currentIndex]
				currentCardInfoResMap["overdue"] = append(currentCardInfoResMap["overdue"], &currentCardInfoList[currentIndex])
				currentIndex += 1
			} else {
				currentCardInfoMap["overdue"+re.EntityGrade+re.EntityCategory].Num += re.PlanInsideOverdue
			}
		}

		// 计划外
		if re.PlanOutsideNotStarted > 0 {
			if _, ok := notCurrentCardInfoMap["not_started"+re.EntityGrade+re.EntityCategory]; !ok {
				notCurrentCardInfoList = append(notCurrentCardInfoList, types.CardInfoItemStruct{
					Name1: re.EntityGrade,
					Name2: re.EntityCategory,
					Num:   re.PlanOutsideNotStarted,
				})
				notCurrentCardInfoMap["not_started"+re.EntityGrade+re.EntityCategory] = &notCurrentCardInfoList[notCurrentIndex]

				notCurrentCardInfoResMap["not_started"] = append(notCurrentCardInfoResMap["not_started"], &notCurrentCardInfoList[notCurrentIndex])
				notCurrentIndex += 1
			} else {
				notCurrentCardInfoMap["not_started"+re.EntityGrade+re.EntityCategory].Num += re.PlanOutsideNotStarted
			}
		}
		if re.PlanOutsideInprogress > 0 {
			if _, ok := notCurrentCardInfoMap["processing"+re.EntityGrade+re.EntityCategory]; !ok {
				notCurrentCardInfoList = append(notCurrentCardInfoList, types.CardInfoItemStruct{
					Name1: re.EntityGrade,
					Name2: re.EntityCategory,
					Num:   re.PlanOutsideInprogress,
				})
				notCurrentCardInfoMap["processing"+re.EntityGrade+re.EntityCategory] = &notCurrentCardInfoList[notCurrentIndex]
				notCurrentCardInfoResMap["processing"] = append(notCurrentCardInfoResMap["processing"], &notCurrentCardInfoList[notCurrentIndex])
				notCurrentIndex += 1
			} else {
				notCurrentCardInfoMap["processing"+re.EntityGrade+re.EntityCategory].Num += re.PlanOutsideInprogress
			}
		}
		if re.PlanOutsideDone > 0 {
			if _, ok := notCurrentCardInfoMap["completed"+re.EntityGrade+re.EntityCategory]; !ok {
				notCurrentCardInfoList = append(notCurrentCardInfoList, types.CardInfoItemStruct{
					Name1: re.EntityGrade,
					Name2: re.EntityCategory,
					Num:   re.PlanOutsideDone,
				})
				notCurrentCardInfoMap["completed"+re.EntityGrade+re.EntityCategory] = &notCurrentCardInfoList[notCurrentIndex]
				notCurrentCardInfoResMap["completed"] = append(notCurrentCardInfoResMap["completed"], &notCurrentCardInfoList[notCurrentIndex])
				notCurrentIndex += 1
			} else {
				notCurrentCardInfoMap["completed"+re.EntityGrade+re.EntityCategory].Num += re.PlanOutsideDone
			}
		}
	}
	currentMonthItem.CardInfo = currentCardInfoResMap
	notCurrentMonthItem.CardInfo = notCurrentCardInfoResMap

	var notStartCont int64
	for _, v := range currentCardInfoResMap["not_started"] {
		notStartCont += v.Num
	}
	var currentMonthItemColumnItem []types.Column
	currentMonthItemColumnItem = append(currentMonthItemColumnItem, types.Column{
		Name:     "未开始",
		Code:     "not_started",
		TotalNum: notStartCont,
	})
	var processingCont int64
	for _, v := range currentCardInfoResMap["processing"] {
		processingCont += v.Num
	}
	currentMonthItemColumnItem = append(currentMonthItemColumnItem, types.Column{
		Name:     "进行中",
		Code:     "processing",
		TotalNum: processingCont,
	})
	var completedCont int64
	for _, v := range currentCardInfoResMap["completed"] {
		completedCont += v.Num
	}
	currentMonthItemColumnItem = append(currentMonthItemColumnItem, types.Column{
		Name:     "已完成",
		Code:     "completed",
		TotalNum: completedCont,
	})
	var overdueCont int64
	for _, v := range currentCardInfoResMap["overdue"] {
		overdueCont += v.Num
	}
	currentMonthItemColumnItem = append(currentMonthItemColumnItem, types.Column{
		Name:     "已逾期",
		Code:     "overdue",
		TotalNum: overdueCont,
	})

	var notStarted int64
	for _, v := range notCurrentCardInfoResMap["not_started"] {
		notStarted += v.Num
	}
	var notCurrentMonthItemColumnItem []types.Column
	notCurrentMonthItemColumnItem = append(notCurrentMonthItemColumnItem, types.Column{
		Name:     "未开始",
		Code:     "not_started",
		TotalNum: notStarted,
	})
	var notProcessingCount int64
	for _, v := range notCurrentCardInfoResMap["processing"] {
		notProcessingCount += v.Num
	}
	notCurrentMonthItemColumnItem = append(notCurrentMonthItemColumnItem, types.Column{
		Name:     "进行中",
		Code:     "processing",
		TotalNum: notProcessingCount,
	})
	var notCompletedCount int64
	for _, v := range notCurrentCardInfoResMap["completed"] {
		notCompletedCount += v.Num
	}
	notCurrentMonthItemColumnItem = append(notCurrentMonthItemColumnItem, types.Column{
		Name:     "已完成",
		Code:     "completed",
		TotalNum: notCompletedCount,
	})

	currentMonthItem.Column = currentMonthItemColumnItem
	notCurrentMonthItem.Column = notCurrentMonthItemColumnItem
	res = types.DeliverRes{
		Month:         currentMonthItem,
		NotMonth:      notCurrentMonthItem,
		MonthCount:    notStartCont + processingCont + completedCont + overdueCont,
		NotMonthCount: notStarted + notProcessingCount + notCompletedCount,
	}
	return
}

// StepCategoryDevotedList 环节投入
func (S ScheduleInfo) StepCategoryDevotedList(Req types.StepCategoryDevotedReq, userId, tenantId int64) (res types.StepCategoryInvestmentRes, err error) {

	var stepCategoryInvestmentResItemList types.DepartmentRequiresCountList
	if err != nil {
		return
	}
	from, to := MonthIntervalTime("2006-01", Req.Month)
	Req.FromTimestamp = from
	Req.ToTimestamp = to

	projectService := Project{}
	allProjectIdList, err := projectService.GetUserProjectByIds(userId, tenantId)
	if err != nil || len(allProjectIdList) == 0 {
		return
	}
	var userIdList, departmentIdList []int64

	// 内部制作统计
	// 按用户分组获取指定当前时间范围【未开始】任务数量映射字典
	userNotStartTaskCount, err := countTaskWithStatusByUserIdsGroupByDepartmentIdTenantIdUserId(allProjectIdList, Req, []string{"not_started"}, &userIdList, &departmentIdList)
	if err != nil {
		return
	}

	// 按用户分组获取指定当前时间范围【进行中】任务数量映射字典
	userIPTaskCount, err := countTaskWithStatusByUserIdsGroupByDepartmentIdTenantIdUserId(allProjectIdList, Req, []string{"feedback", "in_progress", "daily"}, &userIdList, &departmentIdList)
	if err != nil {
		return
	}

	// 按用户分组获取指定当前时间范围【已完成】任务数量映射字典
	userDoneTaskCount, err := countTaskWithStatusByUserIdsGroupByDepartmentIdTenantIdUserId(allProjectIdList, Req, []string{"done"}, &userIdList, &departmentIdList)
	if err != nil {
		return
	}

	// 按用户分组获取指定租户任务，不同项目【逾期任务】映射字典
	userOverdueTaskCountMap, err := countOverdueTaskByUserIdsGroupByDepartmentIdTenantUserId(allProjectIdList, Req, &userIdList, &departmentIdList)
	if err != nil {
		return
	}
	//按用户+租户分组获取指定当前时间范围【返修次数】映射字典
	userRepairTaskCountMap, err := countRepairTaskByUserIdsGroupByDepartmentIdTenantUserId(allProjectIdList, Req, &userIdList, &departmentIdList)
	if err != nil {
		return
	}
	//按用户+租户分组获取指定当前时间 【逾期总时长】映射字典
	userCountOverdueTimeCountMap, err := countOverdueTimeTaskByUserIdsGroupByDepartmentIdTenantUserId(allProjectIdList, Req, &userIdList, &departmentIdList)
	if err != nil {
		return
	}
	var tmpNotStartTaskCount uint64
	var tmpIPTaskCount uint64
	var tmpDoneTaskCount uint64
	var tmpOverdueTaskCount uint64
	var userRepairTaskCount uint64
	var userOverdueTimeCount uint64

	var userIdMap = make(map[int64]bool)
	var uniqueUserIdList []int64
	var departmentIdMap = make(map[int64]bool)
	var uniqueDepartmentIdList []int64
	for _, i2 := range userIdList {
		if _, ok := userIdMap[i2]; !ok && i2 > 0 {
			userIdMap[i2] = true
			uniqueUserIdList = append(uniqueUserIdList, i2)
		}
	}
	for _, i2 := range departmentIdList {
		if _, ok := departmentIdMap[i2]; !ok && i2 > 0 {
			departmentIdMap[i2] = true
			uniqueDepartmentIdList = append(uniqueDepartmentIdList, i2)
		}
	}

	var userList []model.User
	err = ClickHouse.DB.Model(&model.User{}).Where("id in ?", uniqueUserIdList).Find(&userList).Error
	if err != nil {
		return
	}

	var departmentList []model.Department
	err = ClickHouse.DB.Model(&model.Department{}).Where("id in ?", uniqueDepartmentIdList).Find(&departmentList).Error
	if err != nil {
		return
	}
	var countKey string

	var hasData bool
	var appendDepartmentMap = make(map[int64]*types.StepCategoryDevotedRes, 0)
	var appendUserMap = make(map[uint64]*model.User, 0)
	stepCategoryInvestmentResItemListIndex := 0
	for _, department := range departmentList {
		for ui, user := range userList {
			if _, ok := appendUserMap[user.Id]; !ok {
				appendUserMap[user.Id] = &userList[ui]
			}
			countKey = fmt.Sprintf("%d_%d", user.Id, department.Id)
			tmpIPTaskCount = 0
			tmpNotStartTaskCount = 0
			tmpDoneTaskCount = 0
			tmpOverdueTaskCount = 0
			userRepairTaskCount = 0
			userOverdueTimeCount = 0
			hasData = false
			if _, ok := userIPTaskCount[countKey]; ok {
				tmpIPTaskCount = userIPTaskCount[countKey]
				delete(userIPTaskCount, countKey)
				hasData = true
			}
			if _, ok := userNotStartTaskCount[countKey]; ok {
				tmpNotStartTaskCount = userNotStartTaskCount[countKey]
				delete(userNotStartTaskCount, countKey)
				hasData = true
			}
			if _, ok := userDoneTaskCount[countKey]; ok {
				tmpDoneTaskCount = userDoneTaskCount[countKey]
				delete(userDoneTaskCount, countKey)
				hasData = true
			}
			if _, ok := userOverdueTaskCountMap[countKey]; ok {
				tmpOverdueTaskCount = userOverdueTaskCountMap[countKey]
				delete(userOverdueTaskCountMap, countKey)
				hasData = true
			}
			if _, ok := userRepairTaskCountMap[countKey]; ok {
				userRepairTaskCount = userRepairTaskCountMap[countKey]
				delete(userRepairTaskCountMap, countKey)
				hasData = true
			}
			if _, ok := userCountOverdueTimeCountMap[countKey]; ok {
				userOverdueTimeCount = userCountOverdueTimeCountMap[countKey]
				delete(userCountOverdueTimeCountMap, countKey)
				hasData = true
			}

			if hasData {
				if _, ok := appendDepartmentMap[int64(department.Id)]; !ok {
					stepCategoryInvestmentResItemList = append(stepCategoryInvestmentResItemList, types.StepCategoryDevotedRes{
						Id:                int64(department.Id),
						Name:              department.Name,
						Type:              "department",
						TenantId:          department.TenantId,
						ParentId:          0,
						NotStartTaskCount: 0,
						IpTaskCount:       0,
						DoneTaskCount:     0,
						OverdueTaskCount:  0,
						UserId:            0,
						Role:              "",
					})
					appendDepartmentMap[int64(department.Id)] = &stepCategoryInvestmentResItemList[stepCategoryInvestmentResItemListIndex]
					stepCategoryInvestmentResItemListIndex += 1
				}
				stepCategoryInvestmentResItemList = append(stepCategoryInvestmentResItemList, types.StepCategoryDevotedRes{
					Id:                        0,
					Name:                      user.Name,
					Type:                      "user",
					TenantId:                  department.TenantId,
					ParentId:                  int64(department.Id),
					NotStartTaskCount:         tmpNotStartTaskCount,
					IpTaskCount:               tmpIPTaskCount,
					DoneTaskCount:             tmpDoneTaskCount,
					OverdueTaskCount:          tmpOverdueTaskCount,
					UserId:                    user.Id,
					RepairCount:               userRepairTaskCount,
					OverdueTotalTimeTaskCount: userOverdueTimeCount, // 逾期总时长
				})
				stepCategoryInvestmentResItemListIndex += 1
			}
		}
	}

	var noneDepartmentDataUserMap = make(map[uint64]*types.StepCategoryDevotedRes, 0)
	var noneDepartmentData []types.StepCategoryDevotedRes
	var noneDepartmentDataIndex = 0
	var noneDepartmentDataCountEntity = types.StepCategoryDevotedRes{
		Id:                       -1,
		Name:                     "未知",
		Type:                     "unknown",
		ChildrenUserIdList:       []uint64{},
		ChildrenDepartmentIdList: []uint64{},
	}
	noneDepartmentDataCountEntityChildrenDepartmentIdMap := make(map[uint64]int64, 0)
	noneDepartmentDataCountEntityChildrenUserIdMap := make(map[uint64]int64, 0)
	noneDepartmentDataCountEntityHasData := false
	for s, u := range userIPTaskCount {
		tempSepData := strings.Split(s, "_")
		tempUserId, _ := strconv.ParseUint(tempSepData[0], 10, 64)
		tempDepartmentId, _ := strconv.ParseUint(tempSepData[1], 10, 64)
		if _, ok := appendDepartmentMap[int64(tempUserId)]; ok {
			appendDepartmentMap[int64(tempDepartmentId)].IpTaskCount += u
			continue
		}

		if tempDepartmentId > 0 {
			if _, ok := noneDepartmentDataCountEntityChildrenDepartmentIdMap[tempDepartmentId]; !ok {
				noneDepartmentDataCountEntityChildrenDepartmentIdMap[tempDepartmentId] = 0
				noneDepartmentDataCountEntity.ChildrenDepartmentIdList = append(noneDepartmentDataCountEntity.ChildrenDepartmentIdList, tempDepartmentId)
			}
		}
		if tempUserId > 0 {
			if _, ok := noneDepartmentDataCountEntityChildrenUserIdMap[tempUserId]; !ok {
				noneDepartmentDataCountEntityChildrenUserIdMap[tempUserId] = 0
				noneDepartmentDataCountEntity.ChildrenUserIdList = append(noneDepartmentDataCountEntity.ChildrenUserIdList, tempUserId)
			}
		}
		if _, ok := appendUserMap[tempUserId]; ok {
			if _, ok := noneDepartmentDataUserMap[tempUserId]; ok {
				noneDepartmentDataUserMap[tempUserId].IpTaskCount += u
			} else {
				noneDepartmentData = append(noneDepartmentData, types.StepCategoryDevotedRes{
					Id:          0,
					Name:        appendUserMap[tempUserId].Name,
					Type:        "user",
					TenantId:    0,
					ParentId:    -1,
					IpTaskCount: u,
				})
				noneDepartmentDataUserMap[tempUserId] = &noneDepartmentData[noneDepartmentDataIndex]
				noneDepartmentDataIndex += 1
			}
		} else {
			noneDepartmentDataCountEntity.IpTaskCount += u
			noneDepartmentDataCountEntityHasData = true
		}
	}

	for s, u := range userNotStartTaskCount {
		tempSepData := strings.Split(s, "_")
		tempUserId, _ := strconv.ParseUint(tempSepData[0], 10, 64)
		tempDepartmentId, _ := strconv.ParseUint(tempSepData[1], 10, 64)
		if _, ok := appendDepartmentMap[int64(tempUserId)]; ok {
			appendDepartmentMap[int64(tempDepartmentId)].NotStartTaskCount += u
			continue
		}
		if tempDepartmentId > 0 {
			if _, ok := noneDepartmentDataCountEntityChildrenDepartmentIdMap[tempDepartmentId]; !ok {
				noneDepartmentDataCountEntityChildrenDepartmentIdMap[tempDepartmentId] = 0
				noneDepartmentDataCountEntity.ChildrenDepartmentIdList = append(noneDepartmentDataCountEntity.ChildrenDepartmentIdList, tempDepartmentId)
			}
		}
		if tempUserId > 0 {
			if _, ok := noneDepartmentDataCountEntityChildrenUserIdMap[tempUserId]; !ok {
				noneDepartmentDataCountEntityChildrenUserIdMap[tempUserId] = 0
				noneDepartmentDataCountEntity.ChildrenUserIdList = append(noneDepartmentDataCountEntity.ChildrenUserIdList, tempUserId)
			}
		}
		if _, ok := appendUserMap[tempUserId]; ok {
			if _, ok := noneDepartmentDataUserMap[tempUserId]; ok {
				noneDepartmentDataUserMap[tempUserId].NotStartTaskCount += u
			} else {
				noneDepartmentData = append(noneDepartmentData, types.StepCategoryDevotedRes{
					Id:                0,
					Name:              appendUserMap[tempUserId].Name,
					Type:              "user",
					TenantId:          0,
					ParentId:          -1,
					NotStartTaskCount: u,
				})
				noneDepartmentDataUserMap[tempUserId] = &noneDepartmentData[noneDepartmentDataIndex]
				noneDepartmentDataIndex += 1
			}
		} else {
			noneDepartmentDataCountEntity.NotStartTaskCount += u
			noneDepartmentDataCountEntityHasData = true
		}
	}

	for s, u := range userDoneTaskCount {
		tempSepData := strings.Split(s, "_")
		tempUserId, _ := strconv.ParseUint(tempSepData[0], 10, 64)
		tempDepartmentId, _ := strconv.ParseUint(tempSepData[1], 10, 64)
		if _, ok := appendDepartmentMap[int64(tempUserId)]; ok {
			appendDepartmentMap[int64(tempDepartmentId)].DoneTaskCount += u
			continue
		}
		if tempDepartmentId > 0 {
			if _, ok := noneDepartmentDataCountEntityChildrenDepartmentIdMap[tempDepartmentId]; !ok {
				noneDepartmentDataCountEntityChildrenDepartmentIdMap[tempDepartmentId] = 0
				noneDepartmentDataCountEntity.ChildrenDepartmentIdList = append(noneDepartmentDataCountEntity.ChildrenDepartmentIdList, tempDepartmentId)
			}
		}
		if tempUserId > 0 {
			if _, ok := noneDepartmentDataCountEntityChildrenUserIdMap[tempUserId]; !ok {
				noneDepartmentDataCountEntityChildrenUserIdMap[tempUserId] = 0
				noneDepartmentDataCountEntity.ChildrenUserIdList = append(noneDepartmentDataCountEntity.ChildrenUserIdList, tempUserId)
			}
		}
		if _, ok := appendUserMap[tempUserId]; ok {
			if _, ok := noneDepartmentDataUserMap[tempUserId]; ok {
				noneDepartmentDataUserMap[tempUserId].DoneTaskCount += u
			} else {
				noneDepartmentData = append(noneDepartmentData, types.StepCategoryDevotedRes{
					Id:            0,
					Name:          appendUserMap[tempUserId].Name,
					Type:          "user",
					TenantId:      0,
					ParentId:      -1,
					DoneTaskCount: u,
				})
				noneDepartmentDataUserMap[tempUserId] = &noneDepartmentData[noneDepartmentDataIndex]
				noneDepartmentDataIndex += 1
			}
		} else {
			noneDepartmentDataCountEntity.DoneTaskCount += u
			noneDepartmentDataCountEntityHasData = true
		}
	}

	for s, u := range userOverdueTaskCountMap {
		tempSepData := strings.Split(s, "_")
		tempUserId, _ := strconv.ParseUint(tempSepData[0], 10, 64)
		tempDepartmentId, _ := strconv.ParseUint(tempSepData[1], 10, 64)
		if _, ok := appendDepartmentMap[int64(tempUserId)]; ok {
			appendDepartmentMap[int64(tempDepartmentId)].OverdueTaskCount += u
			continue
		}
		if tempDepartmentId > 0 {
			if _, ok := noneDepartmentDataCountEntityChildrenDepartmentIdMap[tempDepartmentId]; !ok {
				noneDepartmentDataCountEntityChildrenDepartmentIdMap[tempDepartmentId] = 0
				noneDepartmentDataCountEntity.ChildrenDepartmentIdList = append(noneDepartmentDataCountEntity.ChildrenDepartmentIdList, tempDepartmentId)
			}
		}
		if tempUserId > 0 {
			if _, ok := noneDepartmentDataCountEntityChildrenUserIdMap[tempUserId]; !ok {
				noneDepartmentDataCountEntityChildrenUserIdMap[tempUserId] = 0
				noneDepartmentDataCountEntity.ChildrenUserIdList = append(noneDepartmentDataCountEntity.ChildrenUserIdList, tempUserId)
			}
		}
		if _, ok := appendUserMap[tempUserId]; ok {
			if _, ok := noneDepartmentDataUserMap[tempUserId]; ok {
				noneDepartmentDataUserMap[tempUserId].OverdueTaskCount += u
			} else {
				noneDepartmentData = append(noneDepartmentData, types.StepCategoryDevotedRes{
					Id:               0,
					Name:             appendUserMap[tempUserId].Name,
					Type:             "user",
					TenantId:         0,
					ParentId:         -1,
					OverdueTaskCount: u,
				})
				noneDepartmentDataUserMap[tempUserId] = &noneDepartmentData[noneDepartmentDataIndex]
				noneDepartmentDataIndex += 1
			}
		} else {
			noneDepartmentDataCountEntity.OverdueTaskCount += u
			noneDepartmentDataCountEntityHasData = true
		}
	}

	for s, u := range userRepairTaskCountMap {
		tempSepData := strings.Split(s, "_")
		tempUserId, _ := strconv.ParseUint(tempSepData[0], 10, 64)
		tempDepartmentId, _ := strconv.ParseUint(tempSepData[1], 10, 64)
		if _, ok := appendDepartmentMap[int64(tempUserId)]; ok {
			appendDepartmentMap[int64(tempDepartmentId)].RepairCount += u
			continue
		}
		if tempDepartmentId > 0 {
			if _, ok := noneDepartmentDataCountEntityChildrenDepartmentIdMap[tempDepartmentId]; !ok {
				noneDepartmentDataCountEntityChildrenDepartmentIdMap[tempDepartmentId] = 0
				noneDepartmentDataCountEntity.ChildrenDepartmentIdList = append(noneDepartmentDataCountEntity.ChildrenDepartmentIdList, tempDepartmentId)
			}
		}
		if tempUserId > 0 {
			if _, ok := noneDepartmentDataCountEntityChildrenUserIdMap[tempUserId]; !ok {
				noneDepartmentDataCountEntityChildrenUserIdMap[tempUserId] = 0
				noneDepartmentDataCountEntity.ChildrenUserIdList = append(noneDepartmentDataCountEntity.ChildrenUserIdList, tempUserId)
			}
		}
		if _, ok := appendUserMap[tempUserId]; ok {
			if _, ok := noneDepartmentDataUserMap[tempUserId]; ok {
				noneDepartmentDataUserMap[tempUserId].RepairCount += u
			} else {
				noneDepartmentData = append(noneDepartmentData, types.StepCategoryDevotedRes{
					Id:          0,
					Name:        appendUserMap[tempUserId].Name,
					Type:        "user",
					TenantId:    0,
					ParentId:    -1,
					RepairCount: u,
				})
				noneDepartmentDataUserMap[tempUserId] = &noneDepartmentData[noneDepartmentDataIndex]
				noneDepartmentDataIndex += 1
			}
		} else {
			noneDepartmentDataCountEntity.RepairCount += u
			noneDepartmentDataCountEntityHasData = true
		}
	}

	for s, u := range userCountOverdueTimeCountMap {
		tempSepData := strings.Split(s, "_")
		tempUserId, _ := strconv.ParseUint(tempSepData[0], 10, 64)
		tempDepartmentId, _ := strconv.ParseUint(tempSepData[1], 10, 64)
		if _, ok := appendDepartmentMap[int64(tempUserId)]; ok {
			appendDepartmentMap[int64(tempDepartmentId)].OverdueTotalTimeTaskCount += u
			continue
		}
		if tempDepartmentId > 0 {
			if _, ok := noneDepartmentDataCountEntityChildrenDepartmentIdMap[tempDepartmentId]; !ok {
				noneDepartmentDataCountEntityChildrenDepartmentIdMap[tempDepartmentId] = 0
				noneDepartmentDataCountEntity.ChildrenDepartmentIdList = append(noneDepartmentDataCountEntity.ChildrenDepartmentIdList, tempDepartmentId)
			}
		}
		if tempUserId > 0 {
			if _, ok := noneDepartmentDataCountEntityChildrenUserIdMap[tempUserId]; !ok {
				noneDepartmentDataCountEntityChildrenUserIdMap[tempUserId] = 0
				noneDepartmentDataCountEntity.ChildrenUserIdList = append(noneDepartmentDataCountEntity.ChildrenUserIdList, tempUserId)
			}
		}
		if _, ok := appendUserMap[tempUserId]; ok {
			if _, ok := noneDepartmentDataUserMap[tempUserId]; ok {
				noneDepartmentDataUserMap[tempUserId].OverdueTotalTimeTaskCount += u
			} else {
				noneDepartmentData = append(noneDepartmentData, types.StepCategoryDevotedRes{
					Id:                        0,
					Name:                      appendUserMap[tempUserId].Name,
					Type:                      "user",
					TenantId:                  0,
					ParentId:                  -1,
					OverdueTotalTimeTaskCount: u,
				})
				noneDepartmentDataUserMap[tempUserId] = &noneDepartmentData[noneDepartmentDataIndex]
				noneDepartmentDataIndex += 1
			}
		} else {
			noneDepartmentDataCountEntity.OverdueTotalTimeTaskCount += u
			noneDepartmentDataCountEntityHasData = true
		}
	}

	if noneDepartmentDataCountEntityHasData || len(noneDepartmentData) > 0 {
		stepCategoryInvestmentResItemList = append(stepCategoryInvestmentResItemList, noneDepartmentDataCountEntity)
		stepCategoryInvestmentResItemList = append(stepCategoryInvestmentResItemList, noneDepartmentData...)
	}

	// 外部制作统计
	var tenantIdList []int64
	outsideExecuteTaskCountMap, err := S.outsideExecuteTaskCount(allProjectIdList, Req, &tenantIdList)
	if err != nil {
		return
	}
	tenantOverdueTaskCountMap, err := S.countOverdueTaskByUserIdsGroupByTenantId(allProjectIdList, Req, &tenantIdList)
	if err != nil {
		return
	}
	tenantRepairTaskCountMap, err := S.countRepairTaskByUserIdsGroupByTenantId(allProjectIdList, Req, &tenantIdList)
	if err != nil {
		return
	}
	tenantOverdueTimeCountMap, err := S.countOverdueTimeTaskByUserIdsGroupByTenantId(allProjectIdList, Req, &tenantIdList)
	if err != nil {
		return
	}
	var tenantList []model.Tenant
	if len(tenantIdList) > 0 {
		var uniqueTenantIdList []int64
		var tenantIdMap = make(map[int64]bool)
		for _, i2 := range tenantIdList {
			if _, ok := tenantIdMap[i2]; !ok && i2 > 0 {
				uniqueTenantIdList = append(uniqueTenantIdList, i2)
				tenantIdMap[i2] = true
			}
		}
		if len(uniqueTenantIdList) > 0 {
			err = ClickHouse.DB.Model(&model.Tenant{}).Where("id in ?", uniqueTenantIdList).Find(&tenantList).Error
			if err != nil {
				return
			}
		}
	}

	for _, tenant := range tenantList {
		tmpNotStartTaskCount = 0
		tmpIPTaskCount = 0
		tmpDoneTaskCount = 0
		tmpOverdueTaskCount = 0
		userRepairTaskCount = 0
		userOverdueTimeCount = 0
		if _, ok := outsideExecuteTaskCountMap[tenant.Id]; ok {
			tmpNotStartTaskCount = uint64(outsideExecuteTaskCountMap[tenant.Id].NotStartNumber)
			tmpIPTaskCount = uint64(outsideExecuteTaskCountMap[tenant.Id].InProgressNumber)
			tmpDoneTaskCount = uint64(outsideExecuteTaskCountMap[tenant.Id].DoneNumber)
		}
		if _, ok := tenantOverdueTaskCountMap[tenant.Id]; ok {
			tmpOverdueTaskCount = uint64(tenantOverdueTaskCountMap[tenant.Id])
		}
		if _, ok := tenantRepairTaskCountMap[tenant.Id]; ok {
			userRepairTaskCount = uint64(tenantRepairTaskCountMap[tenant.Id])
			hasData = true
		}
		if _, ok := tenantOverdueTimeCountMap[tenant.Id]; ok {
			userOverdueTimeCount = uint64(tenantOverdueTimeCountMap[tenant.Id])
			hasData = true
		}

		stepCategoryInvestmentResItemList = append(stepCategoryInvestmentResItemList, types.StepCategoryDevotedRes{
			Id:                        tenant.Id,
			Name:                      tenant.Name,
			Type:                      "tenant",
			TenantId:                  uint64(tenant.Id),
			ParentId:                  0,
			NotStartTaskCount:         tmpNotStartTaskCount,
			IpTaskCount:               tmpIPTaskCount,
			DoneTaskCount:             tmpDoneTaskCount,
			OverdueTaskCount:          tmpOverdueTaskCount,
			RepairCount:               userRepairTaskCount,
			OverdueTotalTimeTaskCount: userOverdueTimeCount,
			UserId:                    0,
			Role:                      "",
		})
	}
	res = types.StepCategoryInvestmentRes{
		UserCount:       int64(len(userList)),
		DepartmentCount: int64(len(departmentList)),
		List:            stepCategoryInvestmentResItemList,
	}
	return
}

// 按用户分组获取指定当前时间范围任务数量映射字典
func countTaskWithStatusByUserIdsGroupByDepartmentIdTenantIdUserId(allProjectIdList []int64, Req types.StepCategoryDevotedReq, corresponds []string, userIdList, departmentIdList *[]int64) (userTaskVersionCountMap map[string]uint64, err error) {
	var userDepartmentCounts []types.UserDepartmentTenantCount

	var StatusService Status
	ipStatusIds, _ := StatusService.GetStatusIdsByCorrespond(corresponds)
	if len(ipStatusIds) == 0 {
		return
	}

	dbr := ClickHouse.DB.Model(&model.Task{}).
		Where("task.project_id IN (?) and task.executor_type in (?)", allProjectIdList, []string{"default", "inside"}).
		Where("JSONLength(JSONExtractString(task.json, 'task_deprecate_data')) = 0 and simpleJSONExtractInt(task.json,'task_status') <> 3 and simpleJSONExtractUInt(task.json,'task_status') in ?", ipStatusIds).
		Where("task.step_type = 'step'")
	if Req.FromTimestamp > 0 && Req.ToTimestamp > 0 {
		dbr.Where("task.plan_end_time BETWEEN ? AND ?", Req.FromTimestamp, Req.ToTimestamp)
	}

	if Req.ProjectId > 0 {
		dbr.Where("task.project_id = ?", Req.ProjectId)
	}
	if Req.StepCategoryId > 0 {
		dbr.Where("task.step_category_id = ?", Req.StepCategoryId)
	}

	err = dbr.Group("task.executor,task.department_id").
		Select("task.executor as user_id,task.department_id,count(task.id) AS count").
		Find(&userDepartmentCounts).Error

	if err != nil {
		return
	}

	// 生成 user_id,department_id 数据字典
	userTaskVersionCountMap = make(map[string]uint64, 0)
	for _, stepItem := range userDepartmentCounts {
		userTaskVersionCountMap[fmt.Sprintf("%d_%d", stepItem.UserId, stepItem.DepartmentId)] = stepItem.Count
		*userIdList = append(*userIdList, int64(stepItem.UserId))
		*departmentIdList = append(*departmentIdList, int64(stepItem.DepartmentId))
	}
	return
}

// 按用户分组获取指定租户任务，不同项目【逾期任务】映射字典
func countOverdueTaskByUserIdsGroupByDepartmentIdTenantUserId(allProjectIdList []int64, Req types.StepCategoryDevotedReq, userIdList, departmentIdList *[]int64) (userTaskVersionCountMap map[string]uint64, err error) {

	var statusService Status
	notStartedIdList, _ := statusService.GetStatusIdsByCorrespond([]string{"not_started"})
	var userDepartmentCounts []UserDepartmentCount
	dbr := ClickHouse.DB.Model(&model.Task{}).
		Where("task.project_id IN (?) and task.executor_type in (?)", allProjectIdList, []string{"default", "inside"}).
		Where("JSONLength(JSONExtractString(task.json, 'task_deprecate_data')) = 0 and simpleJSONExtractInt(task.json,'task_status') <> 3").
		Where("JSONExtractString(task.json, 'task_is_overdue')='yes'").
		Where("task.step_type = 'step'").
		Where("JSONExtractInt(task.json, 'task_status') IN (?)", notStartedIdList)

	if Req.FromTimestamp > 0 && Req.ToTimestamp > 0 {
		dbr.Where("task.plan_end_time BETWEEN ? AND ?", Req.FromTimestamp, Req.ToTimestamp)
	}

	if Req.ProjectId > 0 {
		dbr.Where("task.project_id in ?", Req.ProjectId)
	}

	if Req.StepCategoryId > 0 {
		dbr.Where("task.step_category_id = ?", Req.StepCategoryId)
	}

	err = dbr.Group("task.executor,task.department_id").
		Select("task.executor as user_id,task.department_id,count(task.id) AS count").
		Find(&userDepartmentCounts).Error

	if err != nil {
		return
	}

	// 生成 user_id 数据字典
	userTaskVersionCountMap = make(map[string]uint64, 0)
	for _, stepItem := range userDepartmentCounts {
		userTaskVersionCountMap[fmt.Sprintf("%d_%d", stepItem.UserId, stepItem.DepartmentId)] = stepItem.Count
		*userIdList = append(*userIdList, int64(stepItem.UserId))
		*departmentIdList = append(*departmentIdList, int64(stepItem.DepartmentId))
	}
	return
}

// 统计外包任务逾期数量
func (S ScheduleInfo) countOverdueTaskByUserIdsGroupByTenantId(allProjectIdList []int64, Req types.StepCategoryDevotedReq, tenantIdList *[]int64) (res map[int64]int64, err error) {

	var tenantCount []types.TenantCount
	var statusService Status
	notStartedIdList, _ := statusService.GetStatusIdsByCorrespond([]string{"not_started"})

	dbr := ClickHouse.DB.Model(&model.Task{}).
		Where("task.project_id IN (?) and task.executor_type in (?)", allProjectIdList, []string{"outside", "tenant_group"}).
		Where("JSONLength(JSONExtractString(task.json, 'task_deprecate_data')) = 0 and simpleJSONExtractInt(task.json,'task_status') <> 3").
		Where("JSONExtractString(task.json, 'task_is_overdue')='yes'").
		Where("task.step_type = 'step'").
		Where("JSONExtractInt(task.json, 'task_status') IN (?)", notStartedIdList)

	if Req.ProjectId > 0 {
		dbr.Where("task.project_id in ?", Req.ProjectId)
	}
	if Req.StepCategoryId > 0 {
		dbr.Where("task.step_category_id = ?", Req.StepCategoryId)
	}
	if Req.FromTimestamp > 0 && Req.ToTimestamp > 0 {
		dbr.Where("task.plan_end_time BETWEEN ? AND ?", Req.FromTimestamp, Req.ToTimestamp)
	}
	err = dbr.Group("task.executor_tenant_id").
		Select("task.executor_tenant_id as tenant_id,count(task.id) AS number").
		Find(&tenantCount).Error

	if err != nil {
		return
	}

	res = make(map[int64]int64, 0)
	for _, tenantItem := range tenantCount {
		res[tenantItem.TenantId] = tenantItem.Number
		*tenantIdList = append(*tenantIdList, tenantItem.TenantId)
	}
	return
}

// 按用户+租户分组获取指定当前时间范围【返修次数】映射字典
func countRepairTaskByUserIdsGroupByDepartmentIdTenantUserId(allProjectIdList []int64, Req types.StepCategoryDevotedReq, userIdList, departmentIdList *[]int64) (userTaskVersionCountMap map[string]uint64, err error) {

	var userDepartmentCounts []UserDepartmentCount

	dbr := ClickHouse.DB.Model(&model.Task{}).
		Joins("JOIN repair_order_affected_task roat on task.id = roat.task_id").
		Where("task.project_id IN (?) and task.executor_type in (?)", allProjectIdList, []string{"default", "inside"})

	if Req.ProjectId > 0 {
		dbr.Where("task.project_id in ?", Req.ProjectId)
	}

	if Req.StepCategoryId > 0 {
		dbr.Where("task.step_category_id in ?", Req.StepCategoryId)
	}
	if Req.FromTimestamp > 0 && Req.ToTimestamp > 0 {
		dbr.Where("task.plan_end_time BETWEEN ? AND ?", Req.FromTimestamp, Req.ToTimestamp)
	}

	err = dbr.Group("task.executor,task.department_id").
		Select("count(distinct task.id) as count,task.department_id,task.executor as user_id").
		Find(&userDepartmentCounts).Error

	if err != nil {
		return
	}

	// 生成 user_id 数据字典
	userTaskVersionCountMap = make(map[string]uint64, 0)
	for _, stepItem := range userDepartmentCounts {
		userTaskVersionCountMap[fmt.Sprintf("%d_%d", stepItem.UserId, stepItem.DepartmentId)] = stepItem.Count
		*userIdList = append(*userIdList, int64(stepItem.UserId))
		*departmentIdList = append(*departmentIdList, int64(stepItem.DepartmentId))
	}

	return
}

// 统计外包任务返修次数
func (S ScheduleInfo) countRepairTaskByUserIdsGroupByTenantId(allProjectIdList []int64, Req types.StepCategoryDevotedReq, tenantIdList *[]int64) (res map[int64]int64, err error) {

	var tenantCount []types.TenantCount

	dbr := ClickHouse.DB.Model(&model.Task{}).
		Joins("join order_task_list otl on otl.task_id = task.id JOIN repair_order_affected_task roat on otl.real_task_id = roat.task_id").
		Where("task.project_id IN (?) and task.executor_type in (?)", allProjectIdList, []string{"outside", "tenant_group"})

	if Req.ProjectId > 0 {
		dbr.Where("task.project_id in ?", Req.ProjectId)
	}

	if Req.StepCategoryId > 0 {
		dbr.Where("task.step_category_id in ?", Req.StepCategoryId)
	}
	if Req.FromTimestamp > 0 && Req.ToTimestamp > 0 {
		dbr.Where("task.plan_end_time BETWEEN ? AND ?", Req.FromTimestamp, Req.ToTimestamp)
	}
	err = dbr.Group("task.executor_tenant_id").
		Select("count(distinct task.id) as number,task.executor_tenant_id as tenant_id").
		Find(&tenantCount).Error

	if err != nil {
		return
	}
	res = make(map[int64]int64, 0)
	for _, tenantItem := range tenantCount {
		res[tenantItem.TenantId] = tenantItem.Number
		*tenantIdList = append(*tenantIdList, tenantItem.TenantId)
	}

	return
}

// 按用户+租户分组获取指定当前时间【逾期总时长】映射字典
func countOverdueTimeTaskByUserIdsGroupByDepartmentIdTenantUserId(allProjectIdList []int64, Req types.StepCategoryDevotedReq, userIdList, departmentIdList *[]int64) (userTaskVersionCountMap map[string]uint64, err error) {

	var statusService Status
	var userDepartmentCounts []UserDepartmentCount
	notStartedIdList, _ := statusService.GetStatusIdsByCorrespond([]string{"not_started"})
	dbr := ClickHouse.DB.Model(&model.Task{}).
		Where("task.project_id IN (?) and task.executor_type in (?)", allProjectIdList, []string{"default", "inside"}).
		Where("JSONLength(JSONExtractString(task.json, 'task_deprecate_data')) = 0 and simpleJSONExtractInt(task.json,'task_status') <> 3").
		Where("task.step_type = 'step'").
		Where("JSONExtractString(task.json, 'task_is_overdue')='yes'").
		Where("JSONExtractInt(task.json, 'task_status') IN (?)", notStartedIdList)

	if Req.ProjectId > 0 {
		dbr.Where("task.project_id in ?", Req.ProjectId)
	}
	if Req.StepCategoryId > 0 {
		dbr.Where("task.step_category_id in ?", Req.StepCategoryId)
	}
	if Req.FromTimestamp > 0 && Req.ToTimestamp > 0 {
		dbr.Where("task.plan_end_time BETWEEN ? AND ?", Req.FromTimestamp, Req.ToTimestamp)
	}

	err = dbr.Group("task.executor,task.department_id").
		Select("task.executor as user_id,task.department_id,sum(dateDiff('day', FROM_UNIXTIME(task.plan_end_time), FROM_UNIXTIME(?))) as count", time.Now().Unix()).
		Find(&userDepartmentCounts).Error

	if err != nil {
		return
	}
	// 生成 user_id 数据字典
	userTaskVersionCountMap = make(map[string]uint64, 0)
	for _, stepItem := range userDepartmentCounts {
		userTaskVersionCountMap[fmt.Sprintf("%d_%d", stepItem.UserId, stepItem.DepartmentId)] = stepItem.Count
		*userIdList = append(*userIdList, int64(stepItem.UserId))
		*departmentIdList = append(*departmentIdList, int64(stepItem.DepartmentId))
	}
	return
}

// 统计外包任务逾期时长
func (S ScheduleInfo) countOverdueTimeTaskByUserIdsGroupByTenantId(allProjectIdList []int64, Req types.StepCategoryDevotedReq, tenantIdList *[]int64) (res map[int64]int64, err error) {
	var statusService Status
	var tenantCount []types.TenantCount
	notStartedIdList, _ := statusService.GetStatusIdsByCorrespond([]string{"not_started"})
	dbr := ClickHouse.DB.Model(&model.Task{}).
		Where("task.project_id IN (?) and task.executor_type in (?)", allProjectIdList, []string{"outside", "tenant_group"}).
		Where("JSONLength(JSONExtractString(task.json, 'task_deprecate_data')) = 0 and simpleJSONExtractInt(task.json,'task_status') <> 3").
		Where("task.step_type = 'step'").
		Where("JSONExtractString(task.json, 'task_is_overdue')='yes'").
		Where("JSONExtractInt(task.json, 'task_status') IN (?)", notStartedIdList)

	if Req.ProjectId > 0 {
		dbr.Where("task.project_id in ?", Req.ProjectId)
	}
	if Req.StepCategoryId > 0 {
		dbr.Where("task.step_category_id in ?", Req.StepCategoryId)
	}
	if Req.FromTimestamp > 0 && Req.ToTimestamp > 0 {
		dbr.Where("task.plan_end_time BETWEEN ? AND ?", Req.FromTimestamp, Req.ToTimestamp)
	}
	err = dbr.Group("task.executor_tenant_id").
		Select("task.executor_tenant_id as tenant_id,sum(dateDiff('day', FROM_UNIXTIME(task.plan_end_time), FROM_UNIXTIME(?))) as number", time.Now().Unix()).
		Find(&tenantCount).Error

	if err != nil {
		return
	}
	res = make(map[int64]int64, 0)
	for _, tenantItem := range tenantCount {
		res[tenantItem.TenantId] = tenantItem.Number
		*tenantIdList = append(*tenantIdList, tenantItem.TenantId)
	}
	return
}

//ScheduleTaskCount 排期任务统计
func (S ScheduleInfo) ScheduleTaskCount(tenantId int64, userId int64, currentMonthDeliver string, stepCategoryId uint64, taskStatus string, monthTime string, category []string, grade []string, departmentId []uint64, executor []uint64, executorTenantId []uint64) (res []types.ScheduleTaskCountRes, err error) {
	startTime, endTime := MonthIntervalTime("2006-01", monthTime)

	//项目范围限制
	projectIds, errss := GetImUserProjectIdListByRoleCode(userId, tenantId, []string{}, []string{"in_progress"})
	if errss != nil {
		err = errss
		return
	}
	if len(projectIds) == 0 {
		return
	}
	//  currentMonthDeliver 是否当月交付 month_start_time < plan_end_time < month_end_time
	// 非当月交付, (month_start_time < plan_start_time < month_end_time && plan_end_time > month_end_time) || (plan_start_time < month_start_time && plan_end_time > month_end_time)
	dbs := ClickHouse.DB.
		Where("task.project_id in ? and task.step_type = 'step' and  task.step_category_id = ? and JSONLength(JSONExtractString(task.json, 'task_deprecate_data')) = 0 and simpleJSONExtractInt(task.json,'task_status') <> 3", projectIds, stepCategoryId)

	if currentMonthDeliver == "yes" {
		dbs = dbs.Where("task.plan_end_time BETWEEN ? AND ?", startTime, endTime)
	} else {
		dbs = dbs.Where("task.plan_start_time <= ? AND task.plan_end_time > ?", endTime, endTime)
	}

	if len(category) > 0 || len(grade) > 0 {
		stepCategory := model.StepCategory{}
		ClickHouse.DB.Model(&model.StepCategory{}).Where("id = ?", stepCategoryId).First(&stepCategory)
		parentStepCategory := model.StepCategory{}
		ClickHouse.DB.Model(&model.StepCategory{}).Where("id = ?", stepCategory.ParentId).First(&parentStepCategory)
		module := model.Module{}
		ClickHouse.DB.Model(&model.Module{}).Where("id = ?", parentStepCategory.EntityId).First(&module)
		dbs.Where("entity.project_id in ? and entity.module_id=?", projectIds, module.Id)
		if len(category) > 0 {
			dbs.Where(fmt.Sprintf("JSONExtractString(entity.json, '%s_category') in ?", module.Code), category)
		}

		if len(grade) > 0 {
			dbs.Where(fmt.Sprintf("JSONExtractString(entity.json, '%s_grade') in ?", module.Code), grade)
		}
	}

	if len(departmentId) > 0 {
		dbs.Where("task.department_id in ?", departmentId)
	}

	if len(executor) > 0 {
		dbs.Where("task.executor in ?", executor)
	}
	if len(executorTenantId) > 0 {
		dbs.Where("task.executor_tenant_id in ?", executorTenantId)
	}

	//获取未完成的状态
	var StatusService Status
	if taskStatus == "not_started" {
		statusList, errs := StatusService.GetNotStartedStatus()
		if errs != nil {
			err = errs
			return
		}

		var statusIds []int64
		for _, statusItem := range statusList {
			statusIds = append(statusIds, statusItem.Id)
		}
		dbs = dbs.Where("simpleJSONExtractUInt(task.json,'task_status') in ?", statusIds)

		// 未完成 需要获取 已逾期
		var expiredDB = ClickHouse.DB.Model(&model.Task{})
		var unassignedDB = ClickHouse.DB.Model(&model.Task{})
		var executorOtherDB = ClickHouse.DB.Model(&model.Task{})
		var executorIdlingDB = ClickHouse.DB.Model(&model.Task{})

		if len(category) > 0 || len(grade) > 0 {
			expiredDB = ClickHouse.DB.Model(&model.Entity{}).Joins("join task on task.entity_id = entity.id")
			unassignedDB = ClickHouse.DB.Model(&model.Entity{}).Joins("join task on task.entity_id = entity.id")
			executorOtherDB = ClickHouse.DB.Model(&model.Entity{}).Joins("join task on task.entity_id = entity.id")
			executorIdlingDB = ClickHouse.DB.Model(&model.Entity{}).Joins("join task on task.entity_id = entity.id")
		}

		//以逾期
		var expiredCount uint64 = 0
		err = ScheduleTaskCountQuery(expiredDB, dbs, map[string]string{
			"whereQuery": "JSONExtractString(task.json, 'task_is_overdue')='yes'",
			"fields":     "count(id)",
		}, &expiredCount)

		// 未分配
		var unassignedCount uint64 = 0
		unassignedAssignStatus := []string{"'default'", "'department'"}

		err = ScheduleTaskCountQuery(unassignedDB, dbs, map[string]string{
			"whereQuery": fmt.Sprintf("assign_status in (%s)", strings.Join(unassignedAssignStatus, ",")),
			"fields":     "count(id)",
		}, &unassignedCount)

		// 执行人有其他任务

		var executorOtherTaskCount uint64 = 0

		err = ScheduleTaskCountQuery(executorOtherDB, dbs, map[string]string{
			"joinQuery":  "JOIN timelog on timelog.created_by = task.executor and timelog.complete = 'no'",
			"whereQuery": fmt.Sprintf("timelog.tenant_id = %d", tenantId),
			"fields":     "count(distinct task.id)",
		}, &executorOtherTaskCount)

		// 执行人空转
		var executorIdlingTaskCount uint64 = 0
		moduleModel := model.Module{}
		taskModule, errsss := moduleModel.GetByCode("task")
		if errsss != nil {
			err = errsss
			return
		}
		err = ScheduleTaskCountQuery(executorIdlingDB, dbs, map[string]string{
			"joinQuery":  fmt.Sprintf("left join timelog on timelog.link_id = task.id and timelog.tenant_id =%d and timelog.module_id=%d", tenantId, taskModule.Id),
			"whereQuery": fmt.Sprintf("task.assign_status = 'executor' and timelog.id = %d", 0),
			"fields":     "count(distinct task.id)",
		}, &executorIdlingTaskCount)

		res = []types.ScheduleTaskCountRes{
			{
				Type:      "expired",
				TaskCount: expiredCount,
			},
			{
				Type:      "unassigned",
				TaskCount: unassignedCount,
			},
			{
				Type:      "executor_other",
				TaskCount: executorOtherTaskCount,
			},
			{
				Type:      "executor_idling",
				TaskCount: executorIdlingTaskCount,
			},
		}
		return
	} else if taskStatus == "processing" {
		var statusList []model.Status
		statusError := ClickHouse.DB.Model(&model.Status{}).Where("correspond = 'in_progress'").Find(&statusList).Error
		if statusError != nil {
			err = statusError
			return
		}
		var statusIds []int64
		var remakeStatusId int64
		for _, statusItem := range statusList {
			statusIds = append(statusIds, statusItem.Id)
			if statusItem.Code == "remake" {
				remakeStatusId = statusItem.Id
			}
		}
		dbs = dbs.Where("simpleJSONExtractUInt(task.json,'task_status') in ?", statusIds)
		// 已逾期
		specialFilter := make(map[string]string)
		specialFilter["fields"] = "count(task.id) as task_count"
		specialFilter["category"] = strings.Join(category, ",")
		specialFilter["grade"] = strings.Join(grade, ",")
		var expiredCount uint64
		err = AccordingFilterGetStandardProjectTaskCount(dbs, "expired", specialFilter, &expiredCount)
		// 进行中
		var inProgressCount uint64
		err = AccordingFilterGetStandardProjectTaskCount(dbs, "in_progress", specialFilter, &inProgressCount)
		// 返修中
		var remakeCount uint64
		specialFilter["whereQuery"] = fmt.Sprintf("simpleJSONExtractUInt(task.json,'task_status') = %d", remakeStatusId)
		err = AccordingFilterGetStandardProjectTaskCount(dbs, "remake", specialFilter, &remakeCount)
		res = []types.ScheduleTaskCountRes{
			{
				Type:      "expired",
				TaskCount: expiredCount,
			},
			{
				Type:      "in_progress",
				TaskCount: inProgressCount,
			},
			{
				Type:      "remake",
				TaskCount: remakeCount,
			},
		}
	} else if taskStatus == "overdue" {
		// 未开始
		notStartedStatusList, errs := StatusService.GetNotStartedStatus()
		if errs != nil {
			err = errs
			return
		}

		var notStartedStatusIds []string
		for _, notStartedStatusItem := range notStartedStatusList {
			notStartedStatusIds = append(notStartedStatusIds, strconv.FormatInt(notStartedStatusItem.Id, 10))
		}

		var expiredDB = ClickHouse.DB.Model(&model.Task{})
		if len(category) > 0 || len(grade) > 0 {
			expiredDB = ClickHouse.DB.Model(&model.Entity{}).Joins("join task on task.entity_id = entity.id")
		}
		notStartedStatusStr := strings.Join(notStartedStatusIds, ",")

		var notStartedExpiredCount uint64 = 0
		err = ScheduleTaskCountQuery(expiredDB, dbs, map[string]string{
			"whereQuery": fmt.Sprintf("simpleJSONExtractUInt(task.json,'task_status') in (%s) and JSONExtractString(task.json, 'task_is_overdue')='yes'", notStartedStatusStr),
			"fields":     "count(id)",
		}, &notStartedExpiredCount)

		// 进行中
		var processingStatusList []model.Status
		statusError := ClickHouse.DB.Model(&model.Status{}).Where("correspond = 'in_progress'").Find(&processingStatusList).Error
		if statusError != nil {
			err = statusError
			return
		}
		var processingStatusId []string
		for _, processingStatusItem := range processingStatusList {
			processingStatusId = append(processingStatusId, strconv.FormatInt(processingStatusItem.Id, 10))
		}
		var processingExpiredCount uint64
		err = AccordingFilterGetStandardProjectTaskCount(dbs, "expired", map[string]string{
			"whereQuery": fmt.Sprintf("simpleJSONExtractUInt(task.json,'task_status') in (%s)", strings.Join(processingStatusId, ",")),
			"fields":     "count(task.id) as task_count",
			"category":   strings.Join(category, ","),
			"grade":      strings.Join(grade, ","),
		}, &processingExpiredCount)

		res = []types.ScheduleTaskCountRes{
			{
				Type:      "not_started",
				TaskCount: notStartedExpiredCount,
			},
			{
				Type:      "processing",
				TaskCount: processingExpiredCount,
			},
		}
	}
	return
}

//ScheduleStatusTaskCount 排期状态任务统计
func (S ScheduleInfo) ScheduleStatusTaskCount(taskStatus string, statusFilter string, tenantId int64, userId int64, currentMonthDeliver string, stepCategoryId uint64, monthTime string, category []string, grade []string, departmentId []uint64, executor []uint64, executorTenantId []uint64) (res []types.ScheduleStatusTaskCountRes, err error) {
	startTime, endTime := MonthIntervalTime("2006-01", monthTime)
	var StatusService Status
	specialFilter := make(map[string]string)
	specialFilter["fields"] = "p.id as project_id, p.name as project_name,p.type as project_type, count(task.id) as task_count"
	specialFilter["joinQuery"] = "join project p on task.project_id = p.id"
	specialFilter["groupQuery"] = "p.id, p.name, p.type"
	specialFilter["category"] = strings.Join(category, ",")
	specialFilter["grade"] = strings.Join(grade, ",")
	//项目范围限制
	projectIds, errss := GetImUserProjectIdListByRoleCode(userId, tenantId, []string{}, []string{"in_progress"})
	if errss != nil {
		err = errss
	}
	if len(projectIds) == 0 {
		return
	}

	dbs := ClickHouse.DB.
		Where("task.step_category_id = ? and task.step_type = 'step' and task.project_id in (?) and JSONLength(JSONExtractString(task.json, 'task_deprecate_data')) = 0 and simpleJSONExtractInt(task.json,'task_status') <> 3", stepCategoryId, projectIds)

	if currentMonthDeliver == "yes" {
		dbs = dbs.Where("task.plan_end_time BETWEEN ? AND ?", startTime, endTime)
	} else {
		dbs = dbs.Where("task.plan_start_time <= ? AND task.plan_end_time > ?", endTime, endTime)
	}

	if len(category) > 0 || len(grade) > 0 {
		stepCategory := model.StepCategory{}
		ClickHouse.DB.Model(&model.StepCategory{}).Where("id = ?", stepCategoryId).First(&stepCategory)
		parentStepCategory := model.StepCategory{}
		ClickHouse.DB.Model(&model.StepCategory{}).Where("id = ?", stepCategory.ParentId).First(&parentStepCategory)
		module := model.Module{}
		ClickHouse.DB.Model(&model.Module{}).Where("id = ?", parentStepCategory.EntityId).First(&module)
		dbs = dbs.Where("entity.project_id in ? and entity.module_id=?", projectIds, module.Id)
		if len(category) > 0 {
			dbs = dbs.Where(fmt.Sprintf("JSONExtractString(entity.json, '%s_category') in ?", module.Code), category)
		}

		if len(grade) > 0 {
			dbs = dbs.Where(fmt.Sprintf("JSONExtractString(entity.json, '%s_grade') in ?", module.Code), grade)
		}
	}

	if len(departmentId) > 0 {
		dbs.Where("task.department_id in ?", departmentId)
	}

	if len(executor) > 0 {
		dbs.Where("task.executor in ?", executor)
	}
	if len(executorTenantId) > 0 {
		dbs.Where("task.executor_tenant_id in ?", executorTenantId)
	}

	if taskStatus == "not_started" {
		statusList, errs := StatusService.GetNotStartedStatus()
		if errs != nil {
			err = errs
		}

		var statusIds []int64
		for _, statusItem := range statusList {
			statusIds = append(statusIds, statusItem.Id)
		}

		dbs = dbs.Where("simpleJSONExtractUInt(task.json,'task_status') in ?", statusIds)
		taskDB := ClickHouse.DB.Model(&model.Task{})

		if len(category) > 0 || len(grade) > 0 {
			taskDB = ClickHouse.DB.Model(&model.Entity{}).Joins("join task on task.entity_id = entity.id")
		}

		switch statusFilter {
		case "expired": //以逾期
			err = ScheduleTaskCountQuery(taskDB, dbs, map[string]string{
				"whereQuery": "JSONExtractString(task.json, 'task_is_overdue')='yes'",
				"fields":     "task.project_id as project_id,count(task.id) as task_count",
				"groupQuery": "task.project_id",
			}, &res)
			break
		case "unassigned": //未分配任务统计
			unassignedAssignStatus := []string{"'default'", "'department'"}
			err = ScheduleTaskCountQuery(taskDB, dbs, map[string]string{
				"whereQuery": fmt.Sprintf("assign_status in (%s)", strings.Join(unassignedAssignStatus, ",")),
				"fields":     "task.project_id as project_id,count(distinct task.id) as task_count",
				"groupQuery": "task.project_id",
			}, &res)
			break
		case "executor_other": //执行人有其他任务
			err = ScheduleTaskCountQuery(taskDB, dbs, map[string]string{
				"joinQuery":  "JOIN timelog on timelog.created_by = task.executor and timelog.complete = 'no'",
				"whereQuery": fmt.Sprintf("timelog.tenant_id = %d", tenantId),
				"fields":     "task.project_id as project_id,count(distinct task.id) as task_count",
				"groupQuery": "task.project_id",
			}, &res)
			break
		case "executor_idling": //执行人空转
			moduleModel := model.Module{}
			taskModule, errsss := moduleModel.GetByCode("task")
			if errsss != nil {
				err = errsss
				return
			}
			err = ScheduleTaskCountQuery(taskDB, dbs, map[string]string{
				"joinQuery":  fmt.Sprintf("left join timelog on timelog.link_id = task.id and timelog.tenant_id =%d and timelog.module_id=%d", tenantId, taskModule.Id),
				"whereQuery": fmt.Sprintf("task.assign_status = 'executor' and timelog.id = %d", 0),
				"fields":     "task.project_id as project_id,count(task.id) as task_count",
				"groupQuery": "task.project_id",
			}, &res)
			break
		}
	} else if taskStatus == "processing" {
		var statusList []model.Status
		statusError := ClickHouse.DB.Model(&model.Status{}).Where("correspond = 'in_progress'").Find(&statusList).Error
		if statusError != nil {
			err = statusError
			return
		}
		var statusIds []int64
		var remakeStatusId int64
		for _, statusItem := range statusList {
			statusIds = append(statusIds, statusItem.Id)
			if statusItem.Code == "remake" {
				remakeStatusId = statusItem.Id
			}
		}

		dbs = dbs.Where("simpleJSONExtractUInt(task.json,'task_status') in ?", statusIds)

		// 关联项目表进行统计
		if statusFilter == "remake" {
			specialFilter["whereQuery"] = fmt.Sprintf("simpleJSONExtractUInt(task.json,'task_status') = %d", remakeStatusId)
		}
		err = AccordingFilterGetStandardProjectTaskCount(dbs, statusFilter, specialFilter, &res)
	} else if taskStatus == "completed" {
		var status model.Status
		statusError := ClickHouse.DB.Model(&model.Status{}).Where("code = 'final'").First(&status).Error
		if statusError != nil {
			err = statusError
			return
		}

		dbs = dbs.Where("simpleJSONExtractUInt(task.json,'task_status') == ?", status.Id)

		// 关联项目表进行统计
		err = AccordingFilterGetStandardProjectTaskCount(dbs, taskStatus, specialFilter, &res)
	} else if taskStatus == "overdue" {
		switch statusFilter {
		case "not_started": //未开始
			// 未开始
			notStartedStatusList, errs := StatusService.GetNotStartedStatus()
			if errs != nil {
				err = errs
				return
			}

			var notStartedStatusIds []string
			for _, notStartedStatusItem := range notStartedStatusList {
				notStartedStatusIds = append(notStartedStatusIds, strconv.FormatInt(notStartedStatusItem.Id, 10))
			}

			var taskDB = ClickHouse.DB.Model(&model.Task{})
			if len(category) > 0 || len(grade) > 0 {
				taskDB = ClickHouse.DB.Model(&model.Entity{}).Joins("join task on task.entity_id = entity.id")
			}
			notStartedStatusStr := strings.Join(notStartedStatusIds, ",")

			err = ScheduleTaskCountQuery(taskDB, dbs, map[string]string{
				"whereQuery": fmt.Sprintf("simpleJSONExtractUInt(task.json,'task_status') in (%s) and JSONExtractString(task.json, 'task_is_overdue')='yes'", notStartedStatusStr),
				"fields":     "task.project_id as project_id,count(task.id) as task_count",
				"groupQuery": "task.project_id",
			}, &res)
			break
		case "processing": //进行中
			var statusList []model.Status
			statusError := ClickHouse.DB.Model(&model.Status{}).Where("correspond = 'in_progress'").Find(&statusList).Error
			if statusError != nil {
				err = statusError
				return
			}
			var statusIds []string
			for _, statusItem := range statusList {
				statusIds = append(statusIds, strconv.FormatInt(statusItem.Id, 10))
			}
			specialFilter["whereQuery"] = fmt.Sprintf("simpleJSONExtractUInt(task.json,'task_status') in (%s)", strings.Join(statusIds, ","))
			err = AccordingFilterGetStandardProjectTaskCount(dbs, "expired", specialFilter, &res)
			break
		}
	}

	if len(res) == 0 {
		return
	}

	var projectIdList []uint64
	for _, resItem := range res {
		projectIdList = append(projectIdList, resItem.ProjectId)
	}

	var projectList []model.Project
	err = ClickHouse.DB.Model(&model.Project{}).Where("id in ?", projectIdList).Select("id,type,name").Find(&projectList).Error

	projectMap := map[uint64]model.Project{}

	for _, projectItem := range projectList {
		projectMap[projectItem.Id] = projectItem
	}

	for resIndex, resItem := range res {
		if _, ok := projectMap[resItem.ProjectId]; ok {
			resItem.ProjectName = projectMap[resItem.ProjectId].Name
			resItem.ProjectType = projectMap[resItem.ProjectId].Type
			res[resIndex] = resItem
		}
	}

	return
}

// ScheduleNonStandardProjectTaskCompletionCount 非标准项目排期任务完成统计
func (S ScheduleInfo) ScheduleNonStandardProjectTaskCompletionCount(tenantId int64, userId int64, projectId uint64, isAll string, stepCategoryId uint64, currentTime string) (res types.ScheduleNonStandardProjectTaskCompletionCountRes, err error) {
	var finalStatus model.Status
	var tmpCountList types.CompletionItemQuery
	// 获取已完成状态
	statusError := ClickHouse.DB.Model(&model.Status{}).Where("code = 'final'").First(&finalStatus).Error
	if statusError != nil {
		err = statusError
		return
	}
	var projectServices Project
	var projectIds []int64
	projectIds = append(projectIds, int64(projectId))
	if isAll == "yes" {
		// 查询出提供的项目中的成员是否有自己
		projectIds, _ = projectServices.GetUserProjectByIds(userId, tenantId)

		if len(projectIds) == 0 {
			return
		}
	}
	// 获取当月开始时间和结束时间的时间戳（精确到秒
	currentMonthFirstDay, currentMonthLastDay := MonthIntervalTime("2006-01", currentTime)
	dbs := ClickHouse.DB.Model(&model.Plan{})
	// 当月已完成条件语句
	completedFilterQuery := fmt.Sprintf("count((plan.end_time between %d and %d and JSONExtractInt(task.json, 'task_status') == %d) or null) current_month_completed,", currentMonthFirstDay, currentMonthLastDay, finalStatus.Id)
	// 当月未完成条件语句
	undoneFilterQuery := fmt.Sprintf("count((plan.end_time between %d and %d and JSONExtractInt(task.json, 'task_status') != %d) or null) current_month_undone,", currentMonthFirstDay, currentMonthLastDay, finalStatus.Id)
	// 非当月已完成条件语句
	notCurrentMonthCompletedFilterQuery := fmt.Sprintf("count((plan.end_time > %d and plan.start_time <= %d and JSONExtractInt(task.json, 'task_status') == %d) or null) not_current_month_completed,", currentMonthLastDay, currentMonthLastDay, finalStatus.Id)
	// 非当月已完成条件语句
	notCurrentMonthUndoneQuery := fmt.Sprintf("count((plan.end_time > %d and plan.start_time <= %d and JSONExtractInt(task.json, 'task_status') != %d) or null) not_current_month_undone", currentMonthLastDay, currentMonthLastDay, finalStatus.Id)
	err = dbs.Select(completedFilterQuery+undoneFilterQuery+notCurrentMonthCompletedFilterQuery+notCurrentMonthUndoneQuery).
		Joins("join project on project.id = plan.project_id").
		Joins("join task on task.id = plan.task_id").
		Joins("join task_member on task_member.task_id = task.id").
		Where("plan.project_id in (?) and plan.type = 'to_do' and plan.step_category_id = ?", projectIds, stepCategoryId).
		Find(&tmpCountList).
		Error
	res.CurrentMonthCompletion = append(res.CurrentMonthCompletion, types.CompletionItem{
		Code:  "final",
		Count: tmpCountList.CurrentMontCompleted,
	})
	res.CurrentMonthCompletion = append(res.CurrentMonthCompletion, types.CompletionItem{
		Code:  "not_final",
		Count: tmpCountList.CurrentMonthUndone,
	})
	res.NotCurrentMonthCompletion = append(res.NotCurrentMonthCompletion, types.CompletionItem{
		Code:  "final",
		Count: tmpCountList.NotCurrentMontCompleted,
	})
	res.NotCurrentMonthCompletion = append(res.NotCurrentMonthCompletion, types.CompletionItem{
		Code:  "not_final",
		Count: tmpCountList.NotCurrentMonthUndone,
	})
	res.CountCurrentMonthCompletion = tmpCountList.CurrentMontCompleted + tmpCountList.CurrentMonthUndone
	res.CountNotCurrentMonthCompletion = tmpCountList.NotCurrentMontCompleted + tmpCountList.NotCurrentMonthUndone
	return
}

// ScheduleStandardProjectTaskCompletionCount 标准项目排期任务完成统计
func (S ScheduleInfo) ScheduleStandardProjectTaskCompletionCount(tenantId int64, userId int64, projectId uint64, stepCategoryId uint64, month string) (res int64, err error) {

	monthTime, err := time.ParseInLocation("2006-01", month, time.Local)
	if err != nil {
		return
	}
	from := GetFirstDayOfMonth(monthTime)
	to := GetLastDayOfMonth(monthTime)
	fromTimestamp := from.Unix()
	toTimestamp := to.Unix()

	var projectService Project
	totalProjectIdList, err := projectService.GetUserProjectByIds(userId, tenantId)

	if len(totalProjectIdList) == 0 {
		return
	}
	var statusService Status
	notStartedIdList, _ := statusService.GetStatusIdsByCorrespond([]string{"not_started"})
	inProgressIdList, _ := statusService.GetStatusIdsByCorrespond([]string{"in_progress", "daily", "feedback"})
	doneIdList, _ := statusService.GetStatusIdsByCorrespond([]string{"done"})

	var scheduleTaskCountRes []types.ScheduleTaskCountItemQuery
	var countModuleList []model.Module
	err = ClickHouse.DB.Model(&model.Module{}).Where("code in ?", []string{"design", "asset", "level", "shot"}).Find(&countModuleList).Error
	if err != nil {
		return
	}
	var countModuleMap = make(map[string]*model.Module)
	var countModuleIdList = make([]int64, len(countModuleList))
	for i, module := range countModuleList {
		countModuleMap[module.Code] = &countModuleList[i]
		countModuleIdList[i] = module.Id
	}

	query := ClickHouse.DB.Model(&model.Task{}).
		Where("entity_module_id in (?) and project_id in (?) and step_category_id = ? and step_type = 'step'", countModuleIdList, totalProjectIdList, stepCategoryId).
		Select("count((plan_end_time >= ? and plan_end_time <= ? and "+
			"simpleJSONExtractInt(json, 'task_status') in (?)) or null) plan_inside_not_started,"+
			"count((plan_end_time >= ? and plan_end_time <= ? and "+
			"simpleJSONExtractInt(json, 'task_status') in (?)) or null) plan_inside_inprogress,"+
			"count((plan_end_time >= ? and plan_end_time <= ? and "+
			"simpleJSONExtractInt(json, 'task_status') in (?)) or null) plan_inside_done,"+
			"count((plan_end_time >= ? and plan_end_time <= ? and "+
			"simpleJSONExtractInt(json, 'task_status') in (?) and "+
			"simpleJSONExtractString(json, 'task_is_overdue') = 'yes') or null) plan_inside_overdue,"+
			"count((plan_start_time < ? and plan_end_time > ? and "+
			"simpleJSONExtractInt(json, 'task_status') in (?)) or null) plan_outside_not_started,"+
			"count((plan_start_time < ? and plan_end_time > ? and "+
			"simpleJSONExtractInt(json, 'task_status') in (?)) or null) plan_outside_inprogress,"+
			"count((plan_start_time < ? and plan_end_time > ? and "+
			"simpleJSONExtractInt(json, 'task_status') in (?)) or null) plan_outside_done",
			fromTimestamp, toTimestamp, notStartedIdList,
			fromTimestamp, toTimestamp, inProgressIdList,
			fromTimestamp, toTimestamp, doneIdList,
			fromTimestamp, toTimestamp, notStartedIdList,
			toTimestamp, toTimestamp, notStartedIdList,
			toTimestamp, toTimestamp, inProgressIdList,
			toTimestamp, toTimestamp, doneIdList,
		)
	if projectId > 0 {
		query.Where("project_id = ?", projectId)
	}
	err = query.Find(&scheduleTaskCountRes).Error
	if err != nil {
		return
	}
	var tmpCountCurrentMonthCompletion int64
	for _, v := range scheduleTaskCountRes {
		tmpCountCurrentMonthCompletion += v.PlanInsideNotStarted + v.PlanInsideInprogress + v.PlanInsideDone + v.PlanInsideOverdue + v.PlanOutsideNotStarted + v.PlanOutsideInprogress + v.PlanOutsideDone
	}
	res = tmpCountCurrentMonthCompletion
	return
}

// ScheduleNonStandardTaskMemberCount 非标准项目排期任务待办成员统计
func (S ScheduleInfo) ScheduleNonStandardTaskMemberCount(tenantId int64, userId int64, isAll string, projectId uint64, stepCategoryId uint64, page []int) (res []types.ScheduleNonStandardTaskMemberCountRes, err error) {
	var projectServices Project
	var projectIds []int64
	projectIds = append(projectIds, int64(projectId))
	if isAll == "yes" {
		// 查询出提供的项目中的成员是否有自己
		projectIds, _ = projectServices.GetUserProjectByIds(userId, tenantId)

		if len(projectIds) == 0 {
			return
		}
	}
	err = ClickHouse.DB.Model(&model.Plan{}).
		Select("task_member.partner as user_id, count(task.id) as task_sum").
		Joins("join task on task.id = plan.task_id").
		Joins("join task_member on task_member.task_id = task.id").
		Where("plan.project_id in (?) and plan.type = 'to_do' and plan.step_category_id = ?", projectIds, stepCategoryId).
		Offset((page[0] - 1) * page[1]).
		Limit(page[1]).
		Group("task_member.partner").
		Find(&res).
		Error
	if err != nil {
		return
	}
	var userIds []uint64
	for _, resItem := range res {
		userIds = append(userIds, resItem.UserId)
	}
	var userList []UserItem
	err = ClickHouse.DB.Model(&model.User{}).Where("id in ?", userIds).Find(&userList).Error
	if err != nil {
		return
	}
	userMap := make(map[uint64]string)
	for _, item := range userList {
		userMap[item.Id] = item.Name
	}
	for k, resItem := range res {
		if userMap[resItem.UserId] != "" {
			res[k].UserName = userMap[resItem.UserId]
		}
	}
	return
}

// ScheduleNonStandardTaskList 根据项目ID查询非标准项目任务待办
func (S ScheduleInfo) ScheduleNonStandardTaskList(currentMonth string, completion string, projectId uint64, stepCategoryId uint64, currentTime string, page []int) (res []types.ScheduleNonStandardTaskListRes, err error) {
	var finalStatus model.Status
	dbs := ClickHouse.DB.Model(&model.Plan{}).
		Select("plan.id as plan_id, task.id as task_id,task.name as task_name,task.created_by as created_by,plan.start_time as start_time,plan.end_time as end_time,project.name as project_name,plan.entity_id as entity_id").
		Joins("join project on project.id = plan.project_id").
		Joins("join task on task.id = plan.task_id").
		Where("plan.project_id = ? and plan.type = 'to_do' and plan.step_category_id = ?", projectId, stepCategoryId)
	// 获取完成状态
	statusError := ClickHouse.DB.Model(&model.Status{}).Where("code = 'final'").First(&finalStatus).Error
	if statusError != nil {
		err = statusError
		return
	}
	// 获取当前环节
	var stepCategory model.StepCategory
	err = ClickHouse.DB.Model(&model.StepCategory{}).Where("id = ?", stepCategoryId).First(&stepCategory).Error
	if err != nil {
		return
	}
	// 获取当月开始时间和结束时间的时间戳（精确到秒
	currentMonthFirstDay, currentMonthLastDay := MonthIntervalTime("2006-01", currentTime)
	// 区分是否非当月交付
	if currentMonth == "yes" {
		dbs.Where("plan.end_time between ? and ?", currentMonthFirstDay, currentMonthLastDay)
	} else {
		dbs.Where("plan.end_time > ? and plan.start_time <= ?", currentMonthLastDay, currentMonthLastDay)
	}
	// 区分完成情况状态
	if completion == "final" {
		dbs.Where("JSONExtractInt(task.json, 'task_status') == ?", finalStatus.Id)
	} else if completion == "not_final" {
		dbs.Where("JSONExtractInt(task.json, 'task_status') != ?", finalStatus.Id)
	}
	// 获取基本的项目计划任务列表
	err = dbs.Offset((page[0] - 1) * page[1]).
		Limit(page[1]).
		Find(&res).
		Error
	if err != nil {
		return
	}
	// 遍历其他必要的信息关联ID
	var entityIds []uint64
	var taskIds []uint64
	var CreatedBy []uint64
	for _, resItem := range res {
		entityIds = append(entityIds, resItem.EntityId)
		taskIds = append(taskIds, resItem.TaskId)
		CreatedBy = append(CreatedBy, resItem.CreatedBy)
	}
	// 查询待办成员
	var taskMemberList []types.TaskMemberItem
	err = ClickHouse.DB.Model(&model.TaskMember{}).
		Select("task_member.task_id,user.avatar,user.id as user_id,user.name as user_name").
		Joins("join user on user.id = task_member.partner").
		Where("task_member.task_id in ?", taskIds).
		Find(&taskMemberList).
		Error
	// 获取剧集列表
	var episodeList []EpisodeInfoItem
	err = ClickHouse.DB.Model(&model.Entity{}).Where("id in ?", entityIds).Find(&episodeList).Error
	// 获取创建人信息
	var createdByList []UserItem
	err = ClickHouse.DB.Model(&model.User{}).Where("id in ?", CreatedBy).Find(&createdByList).Error
	// 遍历相同任务ID下的用户
	taskMemberMap := make(map[uint64][]types.TaskMemberItem)
	for _, taskMemberItem := range taskMemberList {
		taskMemberMap[taskMemberItem.TaskId] = append(taskMemberMap[taskMemberItem.TaskId], taskMemberItem)
	}
	// 遍历剧集信息重组下标
	episodeMap := make(map[uint64]EpisodeInfoItem)
	for _, episodeItem := range episodeList {
		episodeMap[episodeItem.Id] = episodeItem
	}
	// 遍历创建人信息重组下标
	createdByMap := make(map[uint64]UserItem)
	for _, createdByItem := range createdByList {
		createdByMap[createdByItem.Id] = createdByItem
	}
	// 遍历返回结果组合数据
	for k, resItem := range res {
		if taskMemberMap[resItem.TaskId] != nil {
			res[k].Partner = taskMemberMap[resItem.TaskId]
		}
		if episodeMap[resItem.EntityId] != (EpisodeInfoItem{}) {
			res[k].EpisodeName = episodeMap[resItem.EntityId].Name
		}
		if createdByMap[resItem.CreatedBy] != (UserItem{}) {
			res[k].CreatedByName = createdByMap[resItem.CreatedBy].Name
		}
		res[k].StepCategory = stepCategory.Name
	}
	return
}

// ScheduleNonStandardProjectTaskCount 获取非标准项目任务统计
func (S ScheduleInfo) ScheduleNonStandardProjectTaskCount(tenantId int64, userId int64, TaskStatus string, currentTime string, currentMonthDeliver string, stepCategoryId uint64) (res []types.ScheduleStatusTaskCountRes, err error) {
	var finalStatus model.Status
	// 获取到当前用户可访问哪些项目，返回项目ID集合
	var projectServices Project
	// 查询出提供的项目中的成员是否有自己
	projectIds, _ := projectServices.GetUserProjectByIds(userId, tenantId)

	if len(projectIds) == 0 {
		return
	}
	// 获取完成状态
	statusError := ClickHouse.DB.Model(&model.Status{}).Where("code = 'final'").First(&finalStatus).Error
	if statusError != nil {
		err = statusError
		return
	}
	dbs := ClickHouse.DB.Model(&model.Plan{}).
		Select("project.id as project_id,project.name as project_name,count(task.id) as task_count").
		Joins("join project on project.id = plan.project_id").
		Joins("join task on task.id = plan.task_id").
		Where("plan.project_id in (?) and plan.type = 'to_do' and plan.step_category_id = ?", projectIds, stepCategoryId)
	// 获取当月开始时间和结束时间的时间戳（精确到秒
	currentMonthFirstDay, currentMonthLastDay := MonthIntervalTime("2006-01", currentTime)
	// 区分是否非当月交付
	if currentMonthDeliver == "yes" {
		dbs.Where("plan.end_time between ? and ?", currentMonthFirstDay, currentMonthLastDay)
	} else {
		dbs.Where("plan.end_time > ? and plan.start_time <= ?", currentMonthLastDay, currentMonthLastDay)
	}
	// 区分完成情况状态
	if TaskStatus == "final" {
		dbs.Where("JSONExtractInt(task.json, 'task_status') == ?", finalStatus.Id)
	} else if TaskStatus == "not_final" {
		dbs.Where("JSONExtractInt(task.json, 'task_status') != ?", finalStatus.Id)
	}

	err = dbs.Group("project.id, project.name").Find(&res).Error

	return
}

// NonStandardStepCategoryDevotedList 非标准环节投入
func (S ScheduleInfo) NonStandardStepCategoryDevotedList(tenantId int64, userId int64, Req types.StepCategoryDevotedReq) (departmentList types.CountNonStandardStepCategoryDevotedRes, err error) {
	Req.FromTimestamp, Req.ToTimestamp = MonthIntervalTime("2006-01", Req.Month)

	var projectServices Project
	var projectIds []int64
	var userIds []string
	var userList []model.User
	projectIds = append(projectIds, Req.ProjectId)
	if Req.IsAll == "yes" {
		// 查询出提供的项目中的成员是否有自己
		projectIds, _ = projectServices.GetUserProjectByIds(userId, tenantId)

		if len(projectIds) == 0 {
			return
		}
	}
	// 根据提供的用户ID和租户获取到非标准任务的总数量
	userNonStandardTaskCount, err := countNonStandardStepCategoryDevotedTask(Req, "all", projectIds)
	// 当月
	userNonStandardCurrentMonthTaskCount, err := countNonStandardStepCategoryDevotedTask(Req, "currentMonth", projectIds)
	// 非当月
	userNonStandardNotCurrentMonthTaskCount, err := countNonStandardStepCategoryDevotedTask(Req, "notCurrentMonth", projectIds)
	for key, _ := range userNonStandardTaskCount {
		userIds = append(userIds, key)
	}
	err = ClickHouse.DB.Model(model.User{}).Where("id in ?", userIds).Find(&userList).Error
	if err != nil {
		return
	}
	var tmpNonStandardTaskCount uint64
	var tmpNonStandardCurrentMonthTaskCount uint64
	var tmpNonStandardNotCurrentMonthTaskCount uint64

	var countKey string
	for _, userItem := range userList {

		tmpNonStandardTaskCount = 0
		tmpNonStandardCurrentMonthTaskCount = 0
		tmpNonStandardNotCurrentMonthTaskCount = 0
		countKey = fmt.Sprintf("%d", userItem.Id)

		if _, ok := userNonStandardTaskCount[countKey]; ok {
			tmpNonStandardTaskCount = userNonStandardTaskCount[countKey]
		}
		if _, ok := userNonStandardCurrentMonthTaskCount[countKey]; ok {
			tmpNonStandardCurrentMonthTaskCount = userNonStandardCurrentMonthTaskCount[countKey]
		}
		if _, ok := userNonStandardNotCurrentMonthTaskCount[countKey]; ok {
			tmpNonStandardNotCurrentMonthTaskCount = userNonStandardNotCurrentMonthTaskCount[countKey]
		}
		departmentList.List = append(departmentList.List, types.NonStandardStepCategoryDevotedRes{
			Id:                       userItem.Id,
			Name:                     userItem.Name,
			Type:                     "user",
			NonStandardTaskCount:     tmpNonStandardTaskCount,
			CurrentMonthTaskCount:    tmpNonStandardCurrentMonthTaskCount,
			NotCurrentMonthTaskCount: tmpNonStandardNotCurrentMonthTaskCount,
		})
	}
	departmentList.PeopleCount = int64(len(userNonStandardCurrentMonthTaskCount) + len(userNonStandardNotCurrentMonthTaskCount))
	return
}

// 外包任务 状态数量统计
func (S ScheduleInfo) outsideExecuteTaskCount(allProjectIdList []int64, Req types.StepCategoryDevotedReq, tenantIdList *[]int64) (res map[int64]*types.OutsideExecuteTaskCountRes, err error) {
	var resRef []types.OutsideExecuteTaskCountRes
	var statusService Status
	notStartedIdList, _ := statusService.GetStatusIdsByCorrespond([]string{"not_started"})
	inProgressIdList, _ := statusService.GetStatusIdsByCorrespond([]string{"in_progress", "daily", "feedback"})
	doneIdList, _ := statusService.GetStatusIdsByCorrespond([]string{"done"})
	dbr := ClickHouse.DB.Model(&model.Task{}).
		Where("task.project_id IN (?) and task.executor_type in (?)", allProjectIdList, []string{"outside", "tenant_group"}).
		Where("JSONLength(JSONExtractString(task.json, 'task_deprecate_data')) = 0 and simpleJSONExtractInt(task.json,'task_status') <> 3")
	if Req.FromTimestamp > 0 && Req.ToTimestamp > 0 {
		dbr.Where("task.plan_end_time BETWEEN ? AND ?", Req.FromTimestamp, Req.ToTimestamp)
	}
	if Req.ProjectId > 0 {
		dbr.Where("task.project_id = ?", Req.ProjectId)
	}
	if Req.StepCategoryId > 0 {
		dbr.Where("task.step_category_id = ?", Req.StepCategoryId)
	}

	err = dbr.Group("task.executor_tenant_id").
		Select("task.executor_tenant_id as tenant_id,"+
			"count(simpleJSONExtractUInt(task.json, 'task_status') in (?) or null)  AS not_start_number,"+
			"count(simpleJSONExtractUInt(task.json, 'task_status') in (?) or null)  AS in_progress_number,"+
			"count(simpleJSONExtractUInt(task.json, 'task_status') in (?) or null)  AS done_number", notStartedIdList, inProgressIdList, doneIdList,
		).
		Find(&resRef).Error

	if err != nil {
		return
	}
	res = make(map[int64]*types.OutsideExecuteTaskCountRes, 0)
	for i, tenantCountItem := range resRef {
		res[tenantCountItem.TenantId] = &resRef[i]
		*tenantIdList = append(*tenantIdList, tenantCountItem.TenantId)
	}
	return
}

func (S ScheduleInfo) handleExcepCountData(t *types.StepCategoryInvestmentRes, ipTaskCount map[string]uint64, notStartTaskCount map[string]uint64, doneTaskCount map[string]uint64, overdueTaskCountMap map[string]uint64, repairTaskCountMap map[string]uint64, countOverdueTimeCountMap map[string]uint64, appendDepartmentMap map[int64]bool) {

}

// 按用户分组获取指定状态的任务数量映射字典
func countNonStandardStepCategoryDevotedTask(Req types.StepCategoryDevotedReq, ResType string, projectIds []int64) (userTaskVersionCountMap map[string]uint64, err error) {
	dbr := ClickHouse.DB.Where("plan.type = 'to_do'")
	if len(projectIds) > 0 {
		dbr.Where("plan.project_id in (?)", projectIds)
	}
	if Req.StepCategoryId > 0 {
		dbr.Where("plan.step_category_id = ?", Req.StepCategoryId)
	}
	var userCurrentMonthDepartmentCounts, userNotCurrentMonthDepartmentCounts []types.UserDepartmentTenantCount
	if ResType == "all" || ResType == "currentMonth" {
		// 当月
		userCurrentMonthDepartmentCounts, err = countIsCurrentMonthNonStandardTask(dbr, Req, true)
		if err != nil {
			return
		}
	}
	if ResType == "all" || ResType == "notCurrentMonth" {
		// 非当月
		userNotCurrentMonthDepartmentCounts, err = countIsCurrentMonthNonStandardTask(dbr, Req, false)
		if err != nil {
			return
		}
	}
	// 生成 user_id 数据字典
	var userCurrentMonthIdMap = make(map[string]uint64, 0)
	var userNotCurrentMonthIdMap = make(map[string]uint64, 0)
	var countUserNotCurrentMonthIdMap = make(map[string]uint64, 0)
	if len(userCurrentMonthDepartmentCounts) > 0 {
		for _, stepItem := range userCurrentMonthDepartmentCounts {
			// 先将本月的统计放入总合计当中
			countUserNotCurrentMonthIdMap[fmt.Sprintf("%d", stepItem.UserId)] = stepItem.Count
			userCurrentMonthIdMap[fmt.Sprintf("%d", stepItem.UserId)] = stepItem.Count
		}
	}
	if len(userNotCurrentMonthDepartmentCounts) > 0 {
		for _, stepItem := range userNotCurrentMonthDepartmentCounts {
			userNotCurrentMonthIdMap[fmt.Sprintf("%d", stepItem.UserId)] = stepItem.Count
			// 如果非本月的统计中有用户在本月中也有任务，那么就相加得出全部数量
			if countUserNotCurrentMonthIdMap[fmt.Sprintf("%d", stepItem.UserId)] > 0 {
				countUserNotCurrentMonthIdMap[fmt.Sprintf("%d", stepItem.UserId)] = countUserNotCurrentMonthIdMap[fmt.Sprintf("%d", stepItem.UserId)] + stepItem.Count
			} else {
				// 如果没有就直接将统计放入总合计当中
				countUserNotCurrentMonthIdMap[fmt.Sprintf("%d", stepItem.UserId)] = stepItem.Count
			}
		}
	}
	if ResType == "all" {
		// 全部就将当月和非本月都返回
		userTaskVersionCountMap = countUserNotCurrentMonthIdMap
	} else if ResType == "currentMonth" {
		// 当月只返回当月统计
		userTaskVersionCountMap = userCurrentMonthIdMap
	} else if ResType == "notCurrentMonth" {
		// 非本月只返回非本月统计
		userTaskVersionCountMap = userNotCurrentMonthIdMap
	}
	return
}

//ScheduleTaskCountQuery 未开始统计
func ScheduleTaskCountQuery(db *gorm.DB, dbs *gorm.DB, specialFilter map[string]string, Count interface{}) (err error) {
	if specialFilter["joinQuery"] != "" {
		db = db.Joins(specialFilter["joinQuery"])
	}

	db = db.Where(dbs).Where(specialFilter["whereQuery"])

	if specialFilter["fields"] != "" {
		db = db.Select(specialFilter["fields"])
	}
	if specialFilter["groupQuery"] != "" {
		db = db.Group(specialFilter["groupQuery"])
	}

	err = db.Find(Count).Error

	return
}

// 统计是否非当月的非标准任务数
func countIsCurrentMonthNonStandardTask(dbr *gorm.DB, Req types.StepCategoryDevotedReq, isCurrentMonth bool) (userDepartmentCounts []types.UserDepartmentTenantCount, err error) {
	dbs := ClickHouse.DB.Model(&model.Plan{}).
		Joins("join task on task.id = plan.task_id").
		Joins("join task_member on task_member.task_id = task.id").
		Where(dbr)
	if isCurrentMonth {
		dbs.Where("plan.end_time BETWEEN ? AND ?", Req.FromTimestamp, Req.ToTimestamp)
	} else {
		dbs.Where("plan.end_time > ? and plan.start_time <= ?", Req.ToTimestamp, Req.ToTimestamp)
	}
	err = dbs.Group("task_member.partner").
		Select("task_member.partner as user_id, count(task_member.task_id) as count").
		Find(&userDepartmentCounts).Error
	return
}

// AccordingFilterGetStandardProjectTaskCount 根据动态条件获取项目任务数量
func AccordingFilterGetStandardProjectTaskCount(dbs *gorm.DB, status string, specialFilter map[string]string, Count interface{}) (err error) {
	db := ClickHouse.DB.Model(&model.Task{}).Where(dbs)
	if specialFilter["category"] != "" || specialFilter["grade"] != "" {
		db.Joins("join entity on task.entity_id = entity.id")
	}
	if specialFilter["fields"] != "" {
		db.Select(specialFilter["fields"])
	}
	if specialFilter["joinQuery"] != "" {
		db.Joins(specialFilter["joinQuery"])
	}
	if specialFilter["groupQuery"] != "" {
		db.Group(specialFilter["groupQuery"])
	}
	if specialFilter["whereQuery"] != "" {
		db.Where(specialFilter["whereQuery"])
	}

	switch status {
	case "expired":
		return db.Where("JSONExtractString(task.json, 'task_is_overdue')='yes'").Find(Count).Error
	case "in_progress":
		return db.Where("JSONExtractString(task.json, 'task_is_overdue')!='yes'").Find(Count).Error
	case "remake":
		return db.Find(Count).Error
	case "completed":
		return db.Find(Count).Error
	}
	return
}
